home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UDebug.inc1.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  116.6 KB  |  4,754 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UDebug.inc1.p }
  4. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  5.  
  6. { NMI catcher does not work... probably an A-trap is lowering the priority level }
  7. { Meanwhile, the user can use NMI to get to underlying debuggers (MacsBug, etc.) }
  8.  
  9. {$IFC NOT qDebugTheDebugger}
  10. {$W+}
  11. {$R-}
  12. {$Init-}
  13. {$OV-}
  14. {$ENDC}
  15. {$IFC qNames}
  16. {$D+}
  17. {$ENDC}
  18.  
  19. {$IFC UNDEFINED IncludeDisassembler}
  20. {$SETC IncludeDisassembler := FALSE}                    { Don't automatically include in this version }
  21. {$ENDC}
  22.  
  23. CONST
  24.     kDebugWindowType    = 901;
  25.  
  26.     kHelpRequest        = '?';
  27.     kDontKnow            = ' Huh? ';
  28.  
  29.     kReserve            = 500;                            { Heap space reserved for the debugger's
  30.                                                          use. Too much?, Too little? }
  31.     kRecent             = 63;                            { must be a power of 2 minus 1 }
  32.  
  33.     kDebugSICN            = 901;                            { SICN given to MN }
  34.     { 68000 exception numbers that we intercept }
  35.     exBusError            = 2 * sizeof(Longint);
  36.     exAddressError        = 3 * sizeof(Longint);
  37.     exIllegalInst        = 4 * sizeof(Longint);
  38.     exZeroDivide        = 5 * sizeof(Longint);
  39.     exCheck             = 6 * sizeof(Longint);
  40.     exOverflow            = 7 * sizeof(Longint);
  41.     exLineF             = 11 * sizeof(Longint);
  42.  
  43. TYPE
  44.  
  45.     IEFilePath            = STRING;
  46.     IEFilePathPtr        = ^IEFilePath;
  47.  
  48.     IEFRefNum            = Longint;
  49.     {---}
  50.     ZT                    = (tBegin, tEnd, tExit, tBeginEndPair, { the rest always stop }
  51.                            tProgBreak, tSysError, tVBL, tReadLn);
  52.     ProcPtrPtr            = ^ProcPtr;
  53.  
  54.     HexAddress            = STRING[16];                    { Usually 8-9 chars. Sometimes a _small_
  55.                                                          string constant though. }
  56.  
  57.     QElemWithA5         = RECORD
  58.         OldA5:                Longint;                    { A place to store the old value of A5 since
  59.                                                          when debugging the compiler trashes the
  60.                                                          value of A0 for any locals in the VBL task
  61.                                                          thus makeing the pointer to the
  62.                                                          paramblockrec unavailable }
  63.         A5:                 Longint;                    { The value of A5 will be stored here to be
  64.                                                          available at VBL time }
  65.         q:                    QElem;                        { vbl queue element for changing the cursor}
  66.         END;
  67.  
  68.     VBLInfoPtr            = ^VBLInfo;
  69.     VBLInfo             = RECORD
  70.         aQElemWithA5:        QElemWithA5;                { vbl queue element for changing the cursor
  71.                                                          }
  72.         ch:                 CHAR;                        { character to represent the flag to the
  73.                                                          user with }
  74.         actionProc:         ProcPtr;                    { Pointer to a Proc that takes a boolean. If
  75.                                                          action is required when setting flag }
  76.         desc:                StringHandle;                { a description of the flag's function }
  77.         END;
  78.  
  79.     DebugFEntry         = RECORD
  80.         addr:                BooleanPtr;                 { Pointer to the actual boolean used for the
  81.                                                          flag }
  82.         ch:                 CHAR;                        { character to represent the flag to the
  83.                                                          user with }
  84.         actionProc:         ProcPtr;                    { Pointer to a Proc that takes a boolean. If
  85.                                                          action is required when setting flag }
  86.         desc:                StringHandle;                { a description of the flag's function }
  87.         END;
  88.  
  89.     DebugSEntry         = RECORD
  90.         addr:                Ptr;
  91.         actionProc:         ProcPtr;                    { Pointer to a Function that returns a Ptr.
  92.                                                          If action is required to get addr (pass
  93.                                                          nil for addr) }
  94.         sym:                MAName;
  95.         END;
  96.  
  97.     RecentPC            = RECORD
  98.         thePC:                Longint;
  99.         theZT:                ZT;
  100.         END;
  101.  
  102.     SavedState            = RECORD
  103.         pFocusRec:            FocusRec;                    { Place to stow focus behind MacApp's back }
  104.  
  105.         SaveVisRgn:         RgnHandle;                    { Place to stow the lo-mem save of the
  106.                                                          Vis-Rgn during the Update sequence }
  107.         gCursorRgn:         RgnHandle;                    { the global cursor region }
  108.         gTarget:            TEvtHandler;
  109.         gClickCount:        INTEGER;
  110.         gErrorParm3:        Str255;
  111.         gEventLevel:        INTEGER;
  112.         gIdlePhase:         IdlePhase;
  113.         gInBackground:        BOOLEAN;
  114.         gLastClickPart:     INTEGER;
  115.         gLastDeskAcc:        Longint;
  116.         gLastMsePt:         Point;
  117.         gLastUpTime:        Longint;
  118.         gMainEventMask:     INTEGER;
  119.         gApplication:        TApplication;                { place to stow the application behind
  120.                                                          MacApp's back }
  121.         gBusyTempRgn:        BOOLEAN;
  122.         gUsedBy:            Str255;
  123.         gTempRgn:            RgnHandle;
  124.  
  125.         gIntenseDebugging:    BOOLEAN;
  126.         gDebugPrinting:     BOOLEAN;
  127.         END;
  128.         
  129.     HideType = (RawHide, PartialHide, FullHide);
  130.  
  131.     {$IFC qDebug}
  132.     TDebugApplication    = OBJECT (TApplication)         { Main Event Handler for debug mode, not for
  133.                                                          tracing. }
  134.         PROCEDURE TDebugApplication.IDebugApplication;
  135.         FUNCTION TDebugApplication.DoMenuCommand(aCmdNumber: CmdNumber): TCommand; OVERRIDE;
  136.         FUNCTION TDebugApplication.WMgrToWindow(aWMgrWindow: WindowPtr): TWindow; OVERRIDE;
  137.         FUNCTION TDebugApplication.MenuEvent(menuItem: Longint): TCommand; OVERRIDE;
  138.         FUNCTION TDebugApplication.HandleMouseDown(VAR theEventInfo: EventInfo): TCommand; OVERRIDE;
  139.         FUNCTION TDebugApplication.HandleUpdateEvent(VAR theEventInfo: EventInfo): TCommand;
  140.             OVERRIDE;
  141.         PROCEDURE TDebugApplication.PollEvent(allowApplicationToSleep: BOOLEAN); OVERRIDE;
  142.         PROCEDURE TDebugApplication.HandleEvent(VAR theEvent: EventRecord); OVERRIDE;
  143.         FUNCTION TDebugApplication.HandleAlienEvent(VAR theEventInfo: EventInfo): TCommand; OVERRIDE
  144.             ;
  145.         PROCEDURE TDebugApplication.PostHandleEvent(VAR theEventInfo: EventInfo); OVERRIDE;
  146.         FUNCTION TDebugApplication.HandleKeyDownEvent(VAR theEventInfo: EventInfo): TCommand;
  147.             OVERRIDE;
  148.         FUNCTION TDebugApplication.HandleSystemEvent(VAR theEventInfo: EventInfo): TCommand;
  149.             OVERRIDE;
  150.         END;
  151.     {$EndC}
  152.  
  153. VAR
  154.     {$Push} {$J+}
  155.     pUDebugInitialized: BOOLEAN;
  156.     pCanEnterDebugger:    BOOLEAN;
  157.     pFileName:            Str255;                         { Name of file to intercept for IO }
  158.  
  159.     pDebugWindow:        TWindow;                        { the window object that contains the debug
  160.                                                          window }
  161.     {$Pop}
  162.  
  163.     pMadeNMRequest:     BOOLEAN;                        { Have a pending NM request }
  164.     pNmReq:             NMRec;                            { For notifying user from bg }
  165.     pDisciplineMethodCalls: BOOLEAN;
  166.     pInterceptExceptionVectors: BOOLEAN;                { whether to intercept the 68xxx lo-memory
  167.                                                          exception vectors }
  168.     pCanEnterWriteLn:    BOOLEAN;                        { Flag to keep us from re-entering the
  169.                                                          WriteLn support }
  170.     pAddTextFocusRec:    FocusRec;                        { Place to stow focus behind MacApp's back }
  171.  
  172.     pSavedState:        SavedState;                     { place to record the state of the
  173.                                                          application }
  174.     {$IFC qDebug}
  175.     pDebugApplication:    TDebugApplication;                { the debug event handler }
  176.     {$EndC}
  177.     pDebugView:         TTranscriptView;                { the window object that contains the debug
  178.                                                          window }
  179.     pVBLInfo:            VBLInfo;
  180.  
  181.     pTraceToggle, pTraceEnabled: BOOLEAN;
  182.     pBreakCount:        INTEGER;                        { current number of breakpoints set }
  183.     pBreakClass, pBreakProc: ARRAY [1..10] OF MAName;
  184.     pStackSpace:        Longint;                        { current total stack space; set in %_BP }
  185.     pProcStack:         Longint;                        { current stack space for just last
  186.                                                          procedure to do a %_BP }
  187.     pBreakStack:        Longint;
  188.     pStepOverStackSize: Longint;                        { when stepping the stack to break on if
  189.                                                          same or less }
  190.     pBrProcStack:        Longint;
  191.     pSysErrPatch:        TrapPatch;
  192.     pReserve:            Handle;
  193.  
  194.     pOldexBusError, pOldexAddressError, pOldexIllegalInst, pOldexZeroDivide, pOldexCheck,
  195.     pOldexOverflow, pOldexLineF: ProcPtr;
  196.  
  197.     pMoreMem:            Longint;                        {-1 if no more to see; 0 if more stack trace
  198.                                                          possible, else more memory dump}
  199.     pRecentPC:            ARRAY [0..kRecent] OF RecentPC; { PC ring buffer }
  200.     pRecentIndex:        INTEGER;
  201.  
  202.     pQuietOutput:        BOOLEAN;                        { if TRUE then we should not send trace
  203.                                                          output to debug window }
  204.  
  205.     pMasters:            INTEGER;                        { # available master pointers found by
  206.                                                          latest %_BP or %_EP }
  207.  
  208.     pEnterProc:         Ptr;
  209.     pInspectProc:        Ptr;
  210.     pSymbolProc:        Ptr;
  211.  
  212.     pFlagsInUse:        INTEGER;                        { number of flags currently in use }
  213.     pFlagTable:         ARRAY [1..kMaxFlags] OF DebugFEntry;
  214.     pSymsInUse:         INTEGER;                        { number of symbol table entries in use }
  215.     pSymTable:            ARRAY [1..kMaxSyms] OF DebugSEntry;
  216.  
  217.     pPermFlag:            BOOLEAN;
  218.  
  219.     pTP2PerfGlobals:    TP2PerfGlobals;                 { Pointer to performance globals record
  220.                                                          Non-nil if tools are inited }
  221.  
  222.     fCaptureProc:        ProcPtr;                        { procedure for capturing output; set it
  223.                                                          with DebugCapture }
  224.  
  225.     pFullyHiddenFromMacapp: BOOLEAN;                    { Are we stopped in the read loop }
  226.     pWasAheadOfDebugWindow, pWasFrontWindow: WindowPtr;
  227.     pWasActive:         BOOLEAN;
  228.     pQHdr:                QHdr;                            { Saved Event Queue Header }
  229.     pQSize:             INTEGER;                        { number of events }
  230.  
  231.     discardStr:         MAName;                         { a string that is used as a placeholder in
  232.                                                          any calls where rqd but the result is not
  233.                                                          rqd. Helps to reduce stack requirements }
  234.  
  235.     { the following were locals to MADebuggerMainEntry but… since the debugger is not re-entrant (for now) they can be
  236.     globals and thus available to the procedures that were nested in MADebuggerMainEntry but are no longer.
  237.     Also we knock off about 2k of stack requirements. }
  238.     which:                ZT;
  239.     pLink:                Longint;
  240.     ppc:                Longint;
  241.     aClassName:         MAName;
  242.     aProcName:            MAName;
  243.     aMiscName:            MAName;
  244.     asDecimal, asHex:    Longint;
  245.     pAtBreak:            BOOLEAN;
  246.     callerFrame:        Longint;
  247.     ch:                 CHAR;
  248.     className:            MAName;
  249.     itsFrame:            Longint;
  250.     nextFrame:            Longint;
  251.     nextLevel:            INTEGER;
  252.     {$Ifc qPerform}
  253.     oldState:            BOOLEAN;                        { State of Performance monitoring when
  254.                                                          enterproc called and the state to which
  255.                                                          monitering will return. Performance
  256.                                                          monitering toggle changes this value }
  257.     {$Endc}
  258.     pNextPC:            Longint;
  259.     prevFrame:            Longint;
  260.     procName:            MAName;
  261.     rcvrClass:            MAName;
  262.     rcvrHandle:         HexAddress;
  263.     receiver:            TObject;
  264.     segNum:             INTEGER;
  265.     stkBreak:            BOOLEAN;
  266.     stepBreak:            BOOLEAN;
  267.     str:                MAName;
  268.     waiting:            BOOLEAN;
  269.  
  270. {--------------------------------------------------------------------------------------------------}
  271.     {$Ifc qPerform}
  272.     {$S MADebugger}
  273.  
  274. FUNCTION DebugPerfMonitor(turnOn: BOOLEAN): BOOLEAN;
  275. { Turns performance tracing on and off if installed. }
  276.  
  277.     BEGIN
  278.     IF (pTP2PerfGlobals <> NIL) & pUDebugInitialized THEN
  279.         DebugPerfMonitor := PerfControl(pTP2PerfGlobals, turnOn)
  280.     ELSE
  281.         DebugPerfMonitor := FALSE;
  282.     END;
  283. {$Endc}
  284.  
  285. {$IFC qDebug}
  286. {--------------------------------------------------------------------------------------------------}
  287.  
  288. FUNCTION DevFAccess(fName: UNIV IEFilePathPtr;
  289.                     opCode: Longint;
  290.                     arg: UNIV Longint): Longint;
  291.     C; EXTERNAL;
  292.  
  293. FUNCTION DevClose(fdesc: IEFRefNum): Longint;
  294.     C; EXTERNAL;
  295.  
  296. FUNCTION DevRead(fdesc: IEFRefNum;
  297.                  bufp: UNIV Longint;
  298.                  count: Longint): Longint;
  299.     C; EXTERNAL;
  300.  
  301. FUNCTION DevWrite(fdesc: IEFRefNum;
  302.                   bufp: UNIV Longint;
  303.                   count: Longint): Longint;
  304.     C; EXTERNAL;
  305.  
  306. FUNCTION DevIoctl(fdesc: IEFRefNum;
  307.                   request: Longint;
  308.                   arg: UNIV Longint): Longint;
  309.     C; EXTERNAL;
  310.  
  311. FUNCTION _addDevHandler(slot, dvName, dvFAccess, dvClose, dvRead, dvWrite,
  312.                         dvIoctl: Longint): Longint;
  313.     C; EXTERNAL;
  314.  
  315. {--------------------------------------------------------------------------------------------------}
  316. { The following are assembler routines in UDebug.a }
  317.  
  318. PROCEDURE XDebugSysError;
  319.     EXTERNAL;
  320. { PROCEDURE XDebugNMI;    EXTERNAL; }
  321.  
  322. PROCEDURE XDebugBusError;
  323.     EXTERNAL;
  324.  
  325. PROCEDURE XDebugAddrError;
  326.     EXTERNAL;
  327.  
  328. PROCEDURE XDebugIllInst;
  329.     EXTERNAL;
  330.  
  331. PROCEDURE XDebugZeroDiv;
  332.     EXTERNAL;
  333.  
  334. PROCEDURE XDebugCheck;
  335.     EXTERNAL;
  336.  
  337. PROCEDURE XDebugOverflow;
  338.     EXTERNAL;
  339.  
  340. PROCEDURE XDebugLineF;
  341.     EXTERNAL;
  342.  
  343. PROCEDURE VBLInstall;
  344.     FORWARD;
  345.  
  346. PROCEDURE VBLRemove;
  347.     FORWARD;
  348.  
  349. {--------------------------------------------------------------------------------------------------}
  350.  
  351. FUNCTION SetGetProc(theGetProc: ProcPtr): ProcPtr;
  352.     EXTERNAL;
  353.  
  354. FUNCTION SetPutProc(thePutProc: ProcPtr): ProcPtr;
  355.     EXTERNAL;
  356.  
  357. {--------------------------------------------------------------------------------------------------}
  358.  
  359. FUNCTION CallSymActionProc(actionProc: ProcPtr): Handle;
  360.     INLINE $205F, $4E90;
  361. {  MOVE.L  (A7)+,A0
  362. JSR (A0)
  363. }
  364.  
  365. FUNCTION CallSymbolLookup(VAR sym: Str255;
  366.                           lookerUpper: Ptr): Longint;
  367.     INLINE $205F, $4E90;
  368. {  MOVE.L  (A7)+,A0
  369. JSR (A0)
  370. }
  371.  
  372. PROCEDURE CallInspector(obj: TObject;
  373.                         inspector: Ptr);
  374.     INLINE $205F, $4E90;
  375. {  MOVE.L  (A7)+,A0
  376. JSR (A0)
  377. }
  378.  
  379. FUNCTION CallFlagActionProc(OnOrOff: BOOLEAN;
  380.                             actionProc: ProcPtr): BOOLEAN;
  381.     INLINE $205F, $4E90;
  382. { MOVE.L (A7)+,A0
  383. JSR (A0)
  384. }
  385.  
  386. PROCEDURE CallEnter(entering: BOOLEAN;
  387.                     proc: Ptr);
  388.     INLINE $205F, $4E90;
  389. {  MOVE.L  (A7)+,A0
  390. JSR (A0)
  391. }
  392.  
  393. PROCEDURE CallCapture(textBuf: Ptr;
  394.                       byteCount: INTEGER;
  395.                       captureProc: ProcPtr);
  396.     INLINE $205F, $4E90;
  397. { MOVEA.L (A7)+,A0
  398. JSR (A0)
  399. }
  400.  
  401. PROCEDURE MainHelpProc;
  402.     FORWARD;
  403.  
  404. {--------------------------------------------------------------------------------------------------}
  405. {$S MADebugger}
  406.  
  407. PROCEDURE CurrentCursor(VAR C: Cursor);
  408.  
  409.     BEGIN
  410.     BlockMove(Ptr(GetTheCrsr), Ptr(@C), sizeof(Cursor));
  411.     END;
  412.  
  413. {--------------------------------------------------------------------------------------------------}
  414. {$S MADebugger}
  415.  
  416. FUNCTION YouAreWarned: BOOLEAN;
  417. { Returns true if the super secret power keys are held down.
  418. Used to indicate to the debugger that the programmer wants to flirt with _DANGER_!
  419. If you do this then you're _ON_YOUR_OWN. }
  420.  
  421.     VAR
  422.         aKeyMap:            KeyMap;
  423.         oldState:            INTEGER;
  424.  
  425.     BEGIN
  426.     oldState := IntegerPtr(JournalFlag)^;
  427.     IntegerPtr(JournalFlag)^ := 0;                        { turn off journaling }
  428.     GetKeys(aKeyMap);
  429.     IntegerPtr(JournalFlag)^ := oldState;
  430.     IF aKeyMap[$3B] THEN
  431.         YouAreWarned := true
  432.     ELSE
  433.         YouAreWarned := FALSE;
  434.     END;
  435.  
  436. {--------------------------------------------------------------------------------------------------}
  437. {$S MADebugger}
  438.  
  439. PROCEDURE TDebugApplication.IDebugApplication;
  440.  
  441.     VAR
  442.         aCommandList:        TCommandList;
  443.  
  444.     BEGIN
  445.     fTicksOfLastIdle := 0;
  446.     fTicksTilNextIdle := 0;
  447.     fCommandQueue := NIL;
  448.     fLastCommand := NIL;
  449.  
  450.     IEvtHandler(NIL);
  451.  
  452.     New(aCommandList);
  453.     FailNil(aCommandList);
  454.     aCommandList.ICommandList;
  455.     fCommandQueue := aCommandList;
  456.     {$IFC qDebug}
  457.     fCommandQueue.SetEltType('TCommand');
  458.     {$ENDC}
  459.  
  460.     END;
  461.  
  462. {--------------------------------------------------------------------------------------------------}
  463. {$S MADebugger}
  464.  
  465. FUNCTION TDebugApplication.WMgrToWindow(aWMgrWindow: WindowPtr): TWindow;
  466.  
  467.     VAR
  468.         theWindow:            TWindow;
  469.  
  470.     BEGIN
  471.     theWindow := INHERITED WMgrToWindow(aWMgrWindow);
  472.     { Make sure we only operate on debugger windows here }
  473.     IF (theWindow <> pDebugWindow) & (NOT YouAreWarned) THEN
  474.         theWindow := NIL;
  475.     WMgrToWindow := theWindow;
  476.     END;
  477.  
  478. {--------------------------------------------------------------------------------------------------}
  479. {$S MADebugger}
  480.  
  481. FUNCTION TDebugApplication.DoMenuCommand(aCmdNumber: CmdNumber): TCommand;
  482.  
  483.     BEGIN
  484.     IF YouAreWarned THEN
  485.         DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber)
  486.     ELSE
  487.         BEGIN
  488.         DoMenuCommand := NIL;
  489.         CASE aCmdNumber OF
  490.             cQuit:
  491.                 BEGIN
  492.                 { Be kind to those with TApplication.Close routines }
  493.                 IF pSavedState.gApplication <> NIL THEN
  494.                     gApplication := pSavedState.gApplication;
  495.                 ExitToShell;
  496.                 END;
  497.         END;
  498.         END;
  499.     END;
  500.  
  501. {--------------------------------------------------------------------------------------------------}
  502. {$S MADebugger}
  503.  
  504. FUNCTION TDebugApplication.HandleUpdateEvent(VAR theEventInfo: EventInfo): TCommand;
  505.  
  506.     BEGIN
  507.     IF pDebugWindow.HasPendingUpdate THEN
  508.         BEGIN
  509.         pDebugWindow.Update;
  510.         HandleUpdateEvent := NIL;
  511.         END
  512.     ELSE
  513.         HandleUpdateEvent := INHERITED HandleUpdateEvent(theEventInfo);
  514.     END;
  515.  
  516. {--------------------------------------------------------------------------------------------------}
  517. {$S MADebugger}
  518.  
  519. FUNCTION TDebugApplication.MenuEvent(menuItem: Longint): TCommand;
  520.  
  521.     VAR
  522.         fi:                 FailInfo;
  523.         cmd:                CmdNumber;
  524.         deskAccName:        Str255;
  525.         theMenuNumber:        INTEGER;
  526.         theItemNumber:        INTEGER;
  527.         savedPort:            GrafPtr;
  528.  
  529.     BEGIN
  530.     MenuEvent := NIL;
  531.  
  532.     theMenuNumber := HiWrd(menuItem);
  533.     theItemNumber := LoWrd(menuItem);
  534.  
  535.     IF theMenuNumber <> 0 THEN
  536.         BEGIN
  537.  
  538.         cmd := CmdFromMenuItem(theMenuNumber, theItemNumber);
  539.  
  540.         IF (cmd < 0) & (theMenuNumber = mApple) THEN
  541.             BEGIN
  542.             GetItem(MAGetMenu(mApple), theItemNumber, deskAccName);
  543.             GetPort(savedPort);
  544.             IF OpenDeskAcc(deskAccName) = noErr THEN;    { MultiFinder be good to us! }
  545.             SetPort(savedPort);
  546.             END
  547.         ELSE IF (cmd < cEditBase) | (cmd > cEditLast) | (NOT SystemEdit(cmd - cEditBase)) THEN
  548.             BEGIN
  549.  
  550.             MenuEvent := gTarget.DoMenuCommand(cmd)
  551.  
  552.             END;
  553.         END;
  554.     END;
  555.  
  556. {--------------------------------------------------------------------------------------------------}
  557. {$S MADebugger}
  558.  
  559. FUNCTION TDebugApplication.HandleMouseDown(VAR theEventInfo: EventInfo): TCommand;
  560.  
  561.     VAR
  562.         doClick:            BOOLEAN;
  563.         aWindow:            TWindow;
  564.         aWMgrWindow:        WindowPtr;
  565.         whereMouseDown:     INTEGER;
  566.         sysWindowAct:        BOOLEAN;
  567.         aCommand:            TCommand;
  568.         theMouse:            Point;
  569.         theVMouse:            VPoint;
  570.         hysteresis:         Point;
  571.  
  572.     BEGIN
  573.     HandleMouseDown := NIL;
  574.  
  575.     WITH theEventInfo, thePEvent^ DO
  576.         BEGIN
  577.         whereMouseDown := FindWindow(where, aWMgrWindow);
  578.         aWindow := WMgrToWindow(aWMgrWindow);
  579.         END;
  580.  
  581.     IF whereMouseDown <> inContent THEN
  582.         SetCursor(arrow);
  583.  
  584.     WITH theEventInfo, thePEvent^ DO
  585.         CASE whereMouseDown OF
  586.             inMenuBar:
  587.                 BEGIN
  588.                 HandleMouseDown := MenuEvent(MenuSelect(where));
  589.                 END;
  590.  
  591.             inSysWindow:
  592.                 SystemClick(thePEvent^, aWMgrWindow);
  593.  
  594.             OTHERWISE
  595.                     { if a MacApp window was associated with the WindowPtr then let the window object
  596.                     decide what to do with the mouse click }
  597.                 IF (aWindow <> NIL) & aWindow.Focus THEN { if we can't focus, we're in trouble }
  598.                     BEGIN
  599.                     theMouse := where;
  600.                     GlobalToLocal(theMouse);
  601.                     aWindow.QDToViewPt(theMouse, theVMouse);
  602.                     hysteresis := gStdHysteresis;        { don't want std changed by var }
  603.                     IF aWindow.HandleMouseDown(theVMouse, theEventInfo, hysteresis, aCommand) &
  604.                        (aCommand <> NIL) THEN
  605.                         BEGIN
  606.                         aCommand.fTracksMouse := true;    {??? someday this won't be forced }
  607.                         aCommand.fInitialPt := where;    {??? someday this won't be forced }
  608.                         HandleMouseDown := aCommand;
  609.                         END;
  610.                     END
  611.                 ELSE IF qDebug THEN
  612.                     BEGIN
  613.                     IF aWindow <> NIL THEN
  614.                         ProgramBreak(
  615.                               'In TApplication.HandleMouseDown: couldn''t focus on a window object!'
  616.                                      )
  617.                     ELSE IF gIntenseDebugging THEN
  618.                         WriteLn('Got a mouse event for a non-MacApp, non-system window');
  619.                     END;
  620.  
  621.         END;
  622.     END;
  623.  
  624. {--------------------------------------------------------------------------------------------------}
  625. {$S MADebugger}
  626.  
  627. PROCEDURE SaveEventQueue(save: BOOLEAN);
  628.  
  629.     CONST
  630.         kLMEvtBufCnt        = $154;
  631.  
  632.     BEGIN
  633.     IF save THEN
  634.         BEGIN
  635.         { Save the existing event queue }
  636.         pQHdr := GetEvQHdr^;
  637.         WITH GetEvQHdr^ DO
  638.             BEGIN
  639.             qFlags := 0;
  640.             qHead := NIL;
  641.             qTail := NIL;
  642.             END;
  643.         pQSize := IntegerPtr(kLMEvtBufCnt)^;
  644.         END
  645.     ELSE
  646.         BEGIN
  647.         { Restore the event queue }
  648.         FlushEvents(everyEvent, 0);
  649.         GetEvQHdr^ := pQHdr;
  650.         IntegerPtr(kLMEvtBufCnt)^ := pQSize;
  651.         END;
  652.     END;
  653.  
  654. {--------------------------------------------------------------------------------------------------}
  655. {$S MADebugger}
  656.  
  657. FUNCTION DebugGetActiveWindow: TWindow;
  658.  
  659.     VAR
  660.         oldFloats:            BOOLEAN;
  661.  
  662.     BEGIN
  663.     oldFloats := pDebugWindow.fFloats;
  664.     pDebugWindow.fFloats := FALSE;                        { so the debugger window doesn't get
  665.                                                          reported }
  666.     DebugGetActiveWindow := gApplication.GetActiveWindow;
  667.     pDebugWindow.fFloats := FALSE;
  668.     END;
  669.  
  670. {--------------------------------------------------------------------------------------------------}
  671. {$S MADebugger}
  672.  
  673. FUNCTION DebugGetActiveDocument: TDocument;
  674.  
  675.     BEGIN
  676.     IF DebugGetActiveWindow <> NIL THEN
  677.         DebugGetActiveDocument := DebugGetActiveWindow.fDocument
  678.     ELSE
  679.         DebugGetActiveDocument := NIL;
  680.     END;
  681.  
  682. {--------------------------------------------------------------------------------------------------}
  683. {$S MADebugger}
  684.  
  685. FUNCTION DebugGetLastCommand: TCommand;
  686.  
  687.     BEGIN
  688.     IF pSavedState.gTarget <> NIL THEN
  689.         DebugGetLastCommand := pSavedState.gTarget.GetLastCommand
  690.     ELSE
  691.         DebugGetLastCommand := NIL;
  692.     END;
  693.  
  694. {--------------------------------------------------------------------------------------------------}
  695. {$S MADebugger}
  696.  
  697. PROCEDURE ExchangeHandles(VAR handle1, handle2: UNIV Handle);
  698.  
  699.     VAR
  700.         savedHandle:        Handle;
  701.  
  702.     BEGIN
  703.     savedHandle := handle1;
  704.     handle1 := handle2;
  705.     handle2 := savedHandle;
  706.     END;
  707.  
  708. {--------------------------------------------------------------------------------------------------}
  709. {$S MADebugger}
  710.  
  711. FUNCTION TDebugApplication.HandleKeyDownEvent(VAR theEventInfo: EventInfo): TCommand;
  712.  
  713.     VAR
  714.         ch:                 CHAR;
  715.         keycode:            INTEGER;
  716.  
  717.     BEGIN
  718.     WITH theEventInfo, thePEvent^ DO
  719.         BEGIN
  720.         ch := CHR(BAND(message, charCodeMask));
  721.         keycode := BSR(BAND(message, keyCodeMask), 8);
  722.  
  723.         IF theCmdKey & YouAreWarned THEN
  724.             HandleKeyDownEvent := gTarget.DoCommandKey(ch, theEventInfo)
  725.         ELSE
  726.             HandleKeyDownEvent := gTarget.DoKeyCommand(ch, keycode, theEventInfo);
  727.         END;
  728.     END;
  729.  
  730. {--------------------------------------------------------------------------------------------------}
  731. {$S MADebugger}
  732.  
  733. PROCEDURE RemoveAnyNMRequests;
  734.  
  735.     BEGIN
  736.     IF pMadeNMRequest THEN
  737.         BEGIN
  738.         pMadeNMRequest := FALSE;
  739.         IF gConfiguration.systemVersion >= $0600 THEN
  740.             BEGIN
  741.             {$IFC qMPW31}
  742.             FailOSErr(NMRemove(QElemPtr(@pNmReq)));
  743.             ReleaseResource(pNmReq.nmSIcon);
  744.             {$ELSEC}
  745.             FailOSErr(NMRemove(@pNmReq));
  746.             ReleaseResource(pNmReq.nmIcon);
  747.             {$ENDC}
  748.             END;
  749.  
  750.         END;
  751.     END;
  752.  
  753. {--------------------------------------------------------------------------------------------------}
  754. {$S MADebugger}
  755.  
  756. PROCEDURE InstallAnNMRequest;
  757.  
  758.     BEGIN
  759.     IF NOT pMadeNMRequest THEN
  760.         BEGIN
  761.         pMadeNMRequest := true;
  762.         IF gConfiguration.systemVersion >= $0600 THEN
  763.             BEGIN
  764.             WITH pNmReq DO
  765.                 BEGIN
  766.                 qType := nmType;
  767.                 nmMark := 1;                            { mark in Apple menu }
  768.                 {$IFC qMPW31}
  769.                 nmSIcon := GetResource('SICN', kDebugSICN); {handle to small icon}
  770.                 IF nmSIcon <> NIL THEN
  771.                     HNoPurge(nmSIcon);
  772.                 {$ELSEC}
  773.                 nmIcon := GetResource('SICN', kDebugSICN); {handle to small icon}
  774.                 IF nmIcon <> NIL THEN
  775.                     HNoPurge(nmIcon);
  776.                 {$ENDC}
  777.                 nmSound := Handle( - 1);                {handle to sound record}
  778.                 nmStr := NIL;                            {string to appear in alert}
  779.                 nmResp := NIL;                            {pointer to response routine}
  780.                 nmRefCon := 0;                            {for application use}
  781.                 END;
  782.             {$IFC qMPW31}
  783.             FailOSErr(NMInstall(QElemPtr(@pNmReq)));
  784.             {$ELSEC}
  785.             FailOSErr(NMInstall(@pNmReq));
  786.             {$ENDC}
  787.             END;
  788.  
  789.         END;
  790.     END;
  791.  
  792. {--------------------------------------------------------------------------------------------------}
  793. {$S MADebugger}
  794.  
  795. FUNCTION TDebugApplication.HandleSystemEvent(VAR theEventInfo: EventInfo): TCommand;
  796.  
  797.     VAR
  798.         switchingIn:        BOOLEAN;
  799.         convertClipboard:    BOOLEAN;
  800.         aWindow:            TWindow;
  801.  
  802.     BEGIN
  803.  
  804.     IF NOT YouAreWarned THEN
  805.         BEGIN
  806.         WITH theEventInfo.thePEvent^ DO
  807.             CASE BSR(message, 24) OF
  808.                 kSuspendOrResume:
  809.                     BEGIN
  810.                     switchingIn := Odd(message);
  811.                     IF pDebugWindow.fWMgrWindow = FrontWindow THEN
  812.                         pDebugWindow.Activate(switchingIn);
  813.                     gInBackground := NOT switchingIn;    { for MacApp }
  814.                     RemoveAnyNMRequests;
  815.                     END;
  816.             END;
  817.         END
  818.     ELSE
  819.         WITH theEventInfo.thePEvent^ DO
  820.             CASE BSR(BAND(message, $FF000000), 24) OF
  821.                 kSuspendOrResume:
  822.                     BEGIN
  823.                     switchingIn := Odd(message);
  824.                     convertClipboard := BAND(message, $00000002) <> 0;
  825.  
  826.                     IF switchingIn THEN
  827.                         RegainControl(convertClipboard)
  828.                     ELSE
  829.                         AboutToLoseControl(convertClipboard);
  830.  
  831.                     IF switchingIn THEN
  832.                         aWindow := GetFrontWindow
  833.                     ELSE
  834.                         aWindow := GetActiveWindow;
  835.  
  836.                     IF aWindow <> NIL THEN
  837.                         aWindow.Activate(switchingIn);
  838.                     gInBackground := NOT switchingIn;
  839.                     RemoveAnyNMRequests;
  840.                     END;
  841.             END;
  842.  
  843.     HandleSystemEvent := NIL;
  844.     END;
  845.  
  846. {--------------------------------------------------------------------------------------------------}
  847. {$S MADebugger}
  848.  
  849. FUNCTION TDebugApplication.HandleAlienEvent(VAR theEventInfo: EventInfo): TCommand;
  850. { In the debugger we don't send events down the co-handler chain. }
  851.  
  852.     BEGIN
  853.     HandleAlienEvent := NIL;
  854.     END;
  855.  
  856. {--------------------------------------------------------------------------------------------------}
  857. {$S MADebugger}
  858.  
  859. PROCEDURE TDebugApplication.HandleEvent(VAR theEvent: EventRecord);
  860.  
  861.     VAR
  862.         fi:                 FailInfo;
  863.         commandToPerform:    TCommand;
  864.         theEventInfo:        EventInfo;
  865.  
  866.     BEGIN
  867.     WITH theEventInfo, theEvent DO
  868.         BEGIN
  869.         thePEvent := @theEvent;
  870.         theBtnState := BAND(modifiers, btnState) <> 0;
  871.         theCmdKey := BAND(modifiers, cmdKey) <> 0;
  872.         theShiftKey := BAND(modifiers, shiftKey) <> 0;
  873.         theAlphaLock := BAND(modifiers, alphaLock) <> 0;
  874.         theOptionKey := BAND(modifiers, optionKey) <> 0;
  875.         theControlKey := BAND(modifiers, controlKey) <> 0;
  876.         theAutoKey := what = autoKey;
  877.         theClickCount := gClickCount;
  878.         affectsMenus := true;                            { assume going in that this event affects
  879.                                                          the menus }
  880.         IF NOT YouAreWarned THEN
  881.             affectsMenus := FALSE;                        { not in the debugger they don't }
  882.         END;
  883.  
  884.     DispatchEvent(theEventInfo, commandToPerform);
  885.     IF (commandToPerform = NIL) THEN
  886.         commandToPerform := GetNextCommand;
  887.  
  888.     IF (commandToPerform <> NIL) & (commandToPerform <> NIL) THEN
  889.         PerformCommand(commandToPerform);
  890.  
  891.     IF YouAreWarned THEN
  892.         PostHandleEvent(theEventInfo);
  893.  
  894.     END;
  895.  
  896. {--------------------------------------------------------------------------------------------------}
  897. {$S MADebugger}
  898.  
  899. PROCEDURE TDebugApplication.PostHandleEvent(VAR theEventInfo: EventInfo);
  900.  
  901.     VAR
  902.         sysWindowAct:        BOOLEAN;
  903.         perm:                BOOLEAN;
  904.  
  905.     BEGIN
  906.     IF MenuBarHasPendingUpdate THEN                     { application wants menu bar redrawn }
  907.         SetupTheMenus                                    { …so draw it immediately. }
  908.     ELSE IF theEventInfo.affectsMenus THEN
  909.         InvalidateMenus;
  910.  
  911.     { See if a system window has been activated or deactivated. }
  912.     sysWindowAct := IsDeskAccessory(FrontWindow);
  913.  
  914.     IF sysWindowAct <> gSysWindowActive THEN
  915.         BEGIN
  916.         gSysWindowActive := sysWindowAct;
  917.  
  918.         IF gSysWindowActive THEN                        { deactivating to sys window }
  919.             BEGIN
  920.             AboutToLoseControl(true);
  921.             InvalidateMenuBar;
  922.             END
  923.         ELSE                                            { coming back from sys window }
  924.             RegainControl(true);
  925.         END;
  926.  
  927.     END;
  928.  
  929. {--------------------------------------------------------------------------------------------------}
  930. {$S MADebugger}
  931.  
  932. PROCEDURE TDebugApplication.PollEvent(allowApplicationToSleep: BOOLEAN);
  933.  
  934.     LABEL 1000;
  935.  
  936.     VAR
  937.         ch:                 CHAR;
  938.         theEvent:            EventRecord;
  939.         theEventInfo:        EventInfo;
  940.         r:                    Rect;
  941.         aPartCode:            INTEGER;
  942.         aWMgrWindow:        WindowPtr;
  943.  
  944.         savePort:            GrafPtr;
  945.         savedScript:        INTEGER;
  946.  
  947.         switchingIn:        BOOLEAN;
  948.         pt:                 Point;
  949.         haveChar:            BOOLEAN;
  950.         aEvQElPtr:            EvQElPtr;
  951.         aMessage:            Longint;
  952.         aCommand:            TCommand;
  953.         keycode:            INTEGER;
  954.         hasEvent:            BOOLEAN;
  955.         commandToPerform:    TCommand;
  956.         fi:                 FailInfo;
  957.  
  958.     PROCEDURE HdlPollEvt(error: INTEGER;
  959.                          message: Longint);
  960.  
  961.         BEGIN
  962.         {$IFC qDebug}
  963.         WriteLn;                                        { add a blank line after all the messages
  964.                                                          from Failure }
  965.         {$ENDC}
  966.         gEventLevel := gEventLevel - 1;
  967.         BEGIN
  968.         IF error <> noErr THEN
  969.             BEGIN
  970.             ShowError(error, message);
  971.             END;
  972.         HiliteMenu(0);                                    { Make sure menu isn't left highlighted. }
  973.         GOTO 1000;                                        { Keep the application running. }
  974.         END;
  975.         END;
  976.  
  977.     BEGIN
  978.     gEventLevel := gEventLevel + 1;
  979.     CatchFailures(fi, HdlPollEvt);
  980.     PLflush(output);                                    { guarantee that user can see prompts }
  981.  
  982.     { Blow off the focus }
  983.     gFocusedView := NIL;
  984.  
  985.     IF NOT gInBackground THEN
  986.         HiliteMenu(mDebug);
  987.  
  988.     IF NOT pDebugWindow.IsShown THEN
  989.         BEGIN
  990.         pDebugWindow.Open;
  991.         pDebugView.RevealInsertionPoint;
  992.         END;
  993.  
  994.     SetCursor(arrow);
  995.     IF gTarget.DoIdle(idleBegin) THEN;
  996.  
  997.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  998.         savedScript := SetKeyScript(Font2Script(GrafPtr(pDebugWindow.fWMgrWindow)^.txFont));
  999.  
  1000.     { IF we have any queued commands that have not otherwise been taken care of, now is the time. }
  1001.  
  1002.     commandToPerform := GetNextCommand;
  1003.     IF commandToPerform <> NIL THEN
  1004.         PerformCommand(commandToPerform);
  1005.  
  1006.     IF qNeedsWaitNextEvent | gConfiguration.hasWaitNextEvent THEN
  1007.         hasEvent := WaitNextEvent(everyEvent, theEvent, GetCaretTime, NIL)
  1008.     ELSE
  1009.         BEGIN
  1010.         SystemTask;
  1011.         hasEvent := GetNextEvent(everyEvent, theEvent)
  1012.         END;
  1013.  
  1014.     IF hasEvent THEN
  1015.         BEGIN
  1016.         { package it }
  1017.         HandleEvent(theEvent);
  1018.  
  1019.         END;
  1020.  
  1021.     Success(fi);
  1022.     gEventLevel := gEventLevel - 1;
  1023.  
  1024. 1000:                                                    { Failure re-entry point }
  1025.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  1026.         savedScript := SetKeyScript(savedScript);
  1027.     END;
  1028.  
  1029. {--------------------------------------------------------------------------------------------------}
  1030. {$S MADebugger}
  1031.  
  1032. PROCEDURE WithHideFromMacAppDo(PROCEDURE WhatToDo;
  1033.                                itsHideType: HideType);
  1034. {
  1035. Intended for doit behind macapp's back stuff.
  1036. Fullhide indicates whether to give enough support to fully stop in the debugger
  1037. }
  1038.  
  1039.     VAR
  1040.         oldPerm:            BOOLEAN;
  1041.         oldpCanEnterDebugger: BOOLEAN;
  1042.  
  1043.         oldpFullyHiddenFromMacapp: BOOLEAN;
  1044.         oldpDisciplineMethodCalls: BOOLEAN;
  1045.         oldDebugWindowNextHandler: TEvtHandler;
  1046.         fi:                 FailInfo;
  1047.         OldA5:                Longint;
  1048.         saveResLoad:        BOOLEAN;
  1049.         saveResFile:        INTEGER;
  1050.  
  1051.  
  1052.     PROCEDURE UnloadActivateEvents;
  1053. { Activate events are manufactured by the window manager
  1054. Thus they need to be preserved. The activate event if any
  1055. is retrieved then the procedure recursed to get any more.  Then
  1056. the events are reposted on the application event queue. }
  1057.  
  1058.         VAR
  1059.             theEvent:            EventRecord;
  1060.             aEvQElPtr:            EvQElPtr;
  1061.  
  1062.         BEGIN
  1063.         IF GetNextEvent(activMask, theEvent) THEN
  1064.             BEGIN
  1065.             UnloadActivateEvents;                        { recurse to get more }
  1066.             WITH theEvent DO
  1067.                 BEGIN
  1068.                 IF (PPostEvent(activateEvt, message, aEvQElPtr)) = noErr THEN
  1069.                     aEvQElPtr^.evtQmodifiers := modifiers;
  1070.                 END;
  1071.             END;
  1072.         END;
  1073.  
  1074.     PROCEDURE MiniHide;
  1075.         BEGIN
  1076.         OldA5 := SetCurrentA5;                                {}
  1077.         saveResLoad := GetResLoad;
  1078.         SetResLoad(TRUE);
  1079.         saveResFile := MAUseResFile(gApplicationRefNum);
  1080.         END;
  1081.  
  1082.     PROCEDURE MiniShow;
  1083.         BEGIN
  1084.         IF MAUseResFile(saveResFile) = 0 THEN ;
  1085.         SetResLoad(saveResLoad);
  1086.         OldA5 := SetA5(OldA5);
  1087.         END;
  1088.  
  1089.     PROCEDURE HideFromMacApp;
  1090.  
  1091.         BEGIN
  1092.         MiniHide; { Everyone has to do a MiniHide }
  1093.         oldpFullyHiddenFromMacapp := pFullyHiddenFromMacapp;
  1094.         IF NOT oldpFullyHiddenFromMacapp THEN
  1095.             Case itsHideType of
  1096.             RawHide:
  1097.                 ; { Already done }
  1098.  
  1099.             PartialHide:
  1100.                 BEGIN
  1101.                 oldpCanEnterDebugger := pCanEnterDebugger;
  1102.                 pSavedState.gIntenseDebugging := gIntenseDebugging;
  1103.                 pSavedState.gDebugPrinting := gDebugPrinting;
  1104.  
  1105.                 pCanEnterDebugger := FALSE;
  1106.                 gDebugPrinting := FALSE;
  1107.                 gIntenseDebugging := FALSE;
  1108.  
  1109.                 oldPerm := PermAllocation(FALSE);
  1110.                 oldpDisciplineMethodCalls := DisciplineMethodCalls(FALSE);
  1111.  
  1112.                 GetFocus(pSavedState.pFocusRec);
  1113.                 gPrinting := FALSE;
  1114.                 gDrawingPictScrap := FALSE;
  1115.                 gDrawingPictScrapView := NIL;
  1116.  
  1117.                 pSavedState.gBusyTempRgn := gBusyTempRgn;
  1118.                 pSavedState.gUsedBy := gUsedBy;
  1119.  
  1120.                 gBusyTempRgn := FALSE;
  1121.                 gUsedBy := '';
  1122.                 ExchangeHandles(pSavedState.gTempRgn, gTempRgn);
  1123.                 ExchangeHandles(pSavedState.SaveVisRgn, GetSaveVisRgnPtr^);
  1124.  
  1125.                 END;
  1126.  
  1127.             FullHide:
  1128.                 BEGIN
  1129.                 pFullyHiddenFromMacapp := true;
  1130.                 { make sure this is set to FALSE in case of new EXIT statements }
  1131.                 pPermFlag := PermAllocation(FALSE);
  1132.                 pDisciplineMethodCalls := DisciplineMethodCalls(FALSE);
  1133.                 ShowCursor;
  1134.                 pDebugView.fHelpProc := NIL;
  1135.                 oldDebugWindowNextHandler := pDebugWindow.fNextHandler;
  1136.                 pDebugWindow.fNextHandler := pDebugApplication;
  1137.  
  1138.                 ExchangeHandles(pSavedState.SaveVisRgn, GetSaveVisRgnPtr^);
  1139.  
  1140.                 pSavedState.gTarget := gTarget;
  1141.                 pSavedState.gClickCount := gClickCount;
  1142.                 pSavedState.gErrorParm3 := gErrorParm3;
  1143.                 pSavedState.gEventLevel := gEventLevel;
  1144.                 pSavedState.gIdlePhase := gIdlePhase;
  1145.                 pSavedState.gInBackground := gInBackground;
  1146.                 pSavedState.gLastClickPart := gLastClickPart;
  1147.                 pSavedState.gLastDeskAcc := gLastDeskAcc;
  1148.                 pSavedState.gLastMsePt := gLastMsePt;
  1149.                 pSavedState.gLastUpTime := gLastUpTime;
  1150.                 pSavedState.gMainEventMask := gMainEventMask;
  1151.                 pSavedState.gApplication := gApplication;
  1152.                 pSavedState.gIntenseDebugging := gIntenseDebugging;
  1153.                 pSavedState.gDebugPrinting := gDebugPrinting;
  1154.  
  1155.                 pSavedState.gBusyTempRgn := gBusyTempRgn;
  1156.                 gBusyTempRgn := FALSE;
  1157.                 pSavedState.gUsedBy := gUsedBy;
  1158.                 gUsedBy := '';
  1159.                 ExchangeHandles(pSavedState.gTempRgn, gTempRgn);
  1160.                 ExchangeHandles(pSavedState.gCursorRgn, gCursorRgn);
  1161.  
  1162.                 GetFocus(pSavedState.pFocusRec);
  1163.  
  1164.                  {### NO! pDebugApplication.InvalidateFocus; }
  1165.  
  1166.                 gPrinting := FALSE;
  1167.                 gDrawingPictScrap := FALSE;
  1168.                 gDrawingPictScrapView := NIL;
  1169.  
  1170.                 gApplication := pDebugApplication;
  1171.                 gIntenseDebugging := FALSE;
  1172.                 gDebugPrinting := FALSE;
  1173.  
  1174.                 { Now blow the Focus }
  1175.                 gFocusedView := NIL;
  1176.  
  1177.                 gTarget := pDebugView;
  1178.  
  1179.                 UnloadActivateEvents;
  1180.                 SaveEventQueue(true);
  1181.  
  1182.                 pWasAheadOfDebugWindow := FindWindowBefore(pDebugWindow.fWMgrWindow);
  1183.                 IF FrontWindow <> pDebugWindow.fWMgrWindow THEN
  1184.                     pWasFrontWindow := FrontWindow
  1185.                 ELSE
  1186.                     pWasFrontWindow := NIL;
  1187.  
  1188.                 pWasActive := pDebugWindow.fIsActive;
  1189.  
  1190.                 IF NOT pWasActive THEN
  1191.                     BEGIN
  1192.                     IF NOT pDebugWindow.IsShown THEN
  1193.                         pDebugWindow.Open;
  1194.                     IF true | NOT gInBackground THEN
  1195.                         BEGIN
  1196.                         HiliteWindow(pDebugWindow.fWMgrWindow, true);
  1197.                         IF pWasFrontWindow <> NIL THEN
  1198.                             HiliteWindow(pWasFrontWindow, FALSE);
  1199.                         pDebugWindow.Activate(true);
  1200.                         END;
  1201.                     pDebugView.RevealInsertionPoint;
  1202.                     END;    { NOT pWasActive }
  1203.                 END;        { FullHide }
  1204.             END;            { CASE }
  1205.         END;                { HideFromMacApp }
  1206.  
  1207.     PROCEDURE ShowToMacApp;
  1208.  
  1209.         BEGIN
  1210.         IF NOT oldpFullyHiddenFromMacapp THEN
  1211.             Case itsHideType OF
  1212.             RawHide:
  1213.                 ;    { Everyone has to do a miniShow (see below) }
  1214.  
  1215.             PartialHide:
  1216.                 BEGIN
  1217.                 ExchangeHandles(pSavedState.SaveVisRgn, GetSaveVisRgnPtr^);
  1218.                 SetEmptyRgn(pSavedState.SaveVisRgn);    { make sure the region stays empty }
  1219.                 ExchangeHandles(pSavedState.gTempRgn, gTempRgn);
  1220.                 gBusyTempRgn := pSavedState.gBusyTempRgn;
  1221.                 gUsedBy := pSavedState.gUsedBy;
  1222.  
  1223.                 SetFocus(pSavedState.pFocusRec);
  1224.  
  1225.                 IF DisciplineMethodCalls(oldpDisciplineMethodCalls) THEN;
  1226.                 IF PermAllocation(oldPerm) THEN;
  1227.  
  1228.                 gDebugPrinting := pSavedState.gDebugPrinting;
  1229.                 gIntenseDebugging := pSavedState.gIntenseDebugging;
  1230.                 pCanEnterDebugger := oldpCanEnterDebugger;
  1231.                 END;
  1232.  
  1233.             FullHide:
  1234.                 BEGIN
  1235.                 pDebugView.fHelpProc := @MainHelpProc;
  1236.                 pDebugWindow.fNextHandler := oldDebugWindowNextHandler;
  1237.  
  1238.                 IF (NOT pWasActive) & (NOT gSingleStep) & (pStepOverStackSize = 0) THEN
  1239.                     BEGIN
  1240.                     IF pWasFrontWindow <> NIL THEN
  1241.                         HiliteWindow(pWasFrontWindow, true);
  1242.                     HiliteWindow(pDebugWindow.fWMgrWindow, FALSE);
  1243.                     pDebugWindow.Activate(FALSE);
  1244.                     END
  1245.                 ELSE
  1246.                     pDebugWindow.fIsActive := pWasActive;
  1247.  
  1248.                 IF pWasAheadOfDebugWindow <> NIL THEN
  1249.                     BEGIN
  1250.                     SendBehind(pDebugWindow.fWMgrWindow, pWasAheadOfDebugWindow);
  1251.                     pDebugWindow.Update;
  1252.                     END;
  1253.  
  1254.                 SaveEventQueue(FALSE);
  1255.  
  1256.                 SetFocus(pSavedState.pFocusRec);
  1257.  
  1258.                 gBusyTempRgn := pSavedState.gBusyTempRgn;
  1259.                 gUsedBy := pSavedState.gUsedBy;
  1260.                 ExchangeHandles(pSavedState.gTempRgn, gTempRgn);
  1261.  
  1262.                 gDebugPrinting := pSavedState.gDebugPrinting;
  1263.                 gIntenseDebugging := pSavedState.gIntenseDebugging;
  1264.                 gApplication := pSavedState.gApplication;
  1265.                 gTarget := pSavedState.gTarget;
  1266.                 gClickCount := pSavedState.gClickCount;
  1267.                 gErrorParm3 := pSavedState.gErrorParm3;
  1268.                 gEventLevel := pSavedState.gEventLevel;
  1269.                 gIdlePhase := pSavedState.gIdlePhase;
  1270.                 gInBackground := pSavedState.gInBackground;
  1271.                 gLastClickPart := pSavedState.gLastClickPart;
  1272.                 gLastDeskAcc := pSavedState.gLastDeskAcc;
  1273.                 gLastMsePt := pSavedState.gLastMsePt;
  1274.                 gLastUpTime := pSavedState.gLastUpTime;
  1275.                 gMainEventMask := pSavedState.gMainEventMask;
  1276.  
  1277.                 ExchangeHandles(pSavedState.gCursorRgn, gCursorRgn);
  1278.                 ExchangeHandles(pSavedState.SaveVisRgn, GetSaveVisRgnPtr^);
  1279.  
  1280.                 IF DisciplineMethodCalls(pDisciplineMethodCalls) THEN;
  1281.                 pPermFlag := PermAllocation(pPermFlag);
  1282.                 pFullyHiddenFromMacapp := FALSE;
  1283.                 END;
  1284.             END;
  1285.         MiniShow;
  1286.         END;
  1287.  
  1288.     PROCEDURE HdlFailure(error: INTEGER;
  1289.                          message: Longint);
  1290.  
  1291.         BEGIN
  1292.         ShowToMacApp;
  1293.         pDebugView.EndForce;
  1294.         CallEnter(FALSE, pEnterProc);
  1295.         pCanEnterDebugger := true;
  1296.  
  1297.         END;
  1298.  
  1299.     BEGIN
  1300.     HideFromMacApp;
  1301.     if itsHideType <> RawHide THEN    { Stuff that's mini hidden isn't allowed to fail }
  1302.         CatchFailures(fi, HdlFailure);
  1303.  
  1304.     WhatToDo;
  1305.  
  1306.     if itsHideType <> RawHide THEN
  1307.         Success(fi);
  1308.     ShowToMacApp;
  1309.     END;
  1310.  
  1311. {--------------------------------------------------------------------------------------------------}
  1312. {$S MADebugger}
  1313.  
  1314. FUNCTION DebugReadCh: CHAR;
  1315.  
  1316.     VAR
  1317.         oldHelpProc:        ProcPtr;
  1318.  
  1319.     BEGIN
  1320.     oldHelpProc := pDebugView.fHelpProc;
  1321.     pDebugView.fHelpProc := NIL;
  1322.     REPEAT
  1323.         pDebugApplication.PollEvent(kAllowApplicationToSleep);
  1324.     UNTIL pDebugView.fLastCh <> CHR(0);
  1325.     DebugReadCh := pDebugView.fLastCh;
  1326.     pDebugView.fLastCh := CHR(0);
  1327.     pDebugView.fHelpProc := oldHelpProc;
  1328.     END;
  1329.  
  1330. {--------------------------------------------------------------------------------------------------}
  1331. {$S MADebugger}
  1332.  
  1333. FUNCTION DebugReadLn(buffer: Ptr;
  1334.                      byteCount: INTEGER): Longint;
  1335.  
  1336.     TYPE
  1337.         PA1000                = PACKED ARRAY [0..999] OF CHAR;
  1338.         StrPtr                = ^PA1000;
  1339.  
  1340.     VAR
  1341.         ch:                 CHAR;
  1342.         len:                INTEGER;
  1343.  
  1344.     PROCEDURE WhatToDo;
  1345.  
  1346.         BEGIN
  1347.         len := 0;
  1348.  
  1349.         REPEAT
  1350.             pDebugView.RevealInsertionPoint;
  1351.             ch := DebugReadCh;
  1352.  
  1353.             CASE ch OF
  1354.                 chBackspace:
  1355.                     IF len > 0 THEN
  1356.                         BEGIN
  1357.                         Write(ch);
  1358.                         len := len - 1;
  1359.                         StrPtr(buffer)^[len] := ' ';
  1360.                         END;
  1361.                 OTHERWISE
  1362.                     BEGIN
  1363.                     Write(ch);
  1364.                     StrPtr(buffer)^[len] := ch;
  1365.                     len := len + 1;
  1366.                     END
  1367.             END;
  1368.         UNTIL (ch = chReturn) | (len = byteCount);
  1369.  
  1370.         DebugReadLn := len;
  1371.         END;
  1372.  
  1373.     BEGIN
  1374.     IF FALSE & NOT pFullyHiddenFromMacapp THEN
  1375.         BEGIN
  1376.         which := tReadLn;
  1377.         IF gInBackground THEN
  1378.             InstallAnNMRequest;
  1379.         END;
  1380.     WithHideFromMacAppDo(WhatToDo, FullHide);
  1381.     END;
  1382.  
  1383. {--------------------------------------------------------------------------------------------------}
  1384. {$S MADebugger}
  1385.  
  1386. PROCEDURE InstallInterceptors(install: BOOLEAN);
  1387.  
  1388.     BEGIN
  1389.  
  1390.     IF install THEN
  1391.         BEGIN
  1392.         { Intercept 68000 exceptions }
  1393.         IF pInterceptExceptionVectors THEN
  1394.             BEGIN
  1395.             pOldexBusError := ProcPtrPtr(exBusError)^;
  1396.             ProcPtrPtr(exBusError)^ := @XDebugBusError;
  1397.  
  1398.             pOldexAddressError := ProcPtrPtr(exAddressError)^;
  1399.             ProcPtrPtr(exAddressError)^ := @XDebugAddrError;
  1400.  
  1401.             pOldexIllegalInst := ProcPtrPtr(exIllegalInst)^;
  1402.             ProcPtrPtr(exIllegalInst)^ := @XDebugIllInst;
  1403.  
  1404.             pOldexZeroDivide := ProcPtrPtr(exZeroDivide)^;
  1405.             ProcPtrPtr(exZeroDivide)^ := @XDebugZeroDiv;
  1406.  
  1407.             pOldexCheck := ProcPtrPtr(exCheck)^;
  1408.             ProcPtrPtr(exCheck)^ := @XDebugCheck;
  1409.  
  1410.             pOldexOverflow := ProcPtrPtr(exOverflow)^;
  1411.             ProcPtrPtr(exOverflow)^ := @XDebugOverflow;
  1412.  
  1413.             pOldexLineF := ProcPtrPtr(exLineF)^;
  1414.             ProcPtrPtr(exLineF)^ := @XDebugLineF;
  1415.             END;
  1416.  
  1417.         { Intercept SysError calls }
  1418.         FailOSErr(PatchTrap(pSysErrPatch, _SysError, @XDebugSysError));
  1419.         END
  1420.     ELSE
  1421.         BEGIN
  1422.         { UN-Intercept 68000 exceptions }
  1423.         IF pInterceptExceptionVectors THEN
  1424.             BEGIN
  1425.             IF ProcPtrPtr(exBusError)^ = @XDebugBusError THEN
  1426.                 ProcPtrPtr(exBusError)^ := pOldexBusError;
  1427.  
  1428.             IF ProcPtrPtr(exAddressError)^ = @XDebugAddrError THEN
  1429.                 ProcPtrPtr(exAddressError)^ := pOldexAddressError;
  1430.  
  1431.             IF ProcPtrPtr(exIllegalInst)^ = @XDebugIllInst THEN
  1432.                 ProcPtrPtr(exIllegalInst)^ := pOldexIllegalInst;
  1433.  
  1434.             IF ProcPtrPtr(exZeroDivide)^ = @XDebugZeroDiv THEN
  1435.                 ProcPtrPtr(exZeroDivide)^ := pOldexZeroDivide;
  1436.  
  1437.             IF ProcPtrPtr(exCheck)^ = @XDebugCheck THEN
  1438.                 ProcPtrPtr(exCheck)^ := pOldexCheck;
  1439.  
  1440.             IF ProcPtrPtr(exOverflow)^ = @XDebugOverflow THEN
  1441.                 ProcPtrPtr(exOverflow)^ := pOldexOverflow;
  1442.  
  1443.             IF ProcPtrPtr(exLineF)^ = @XDebugLineF THEN
  1444.                 ProcPtrPtr(exLineF)^ := pOldexLineF;
  1445.             END;
  1446.  
  1447.         { UN-Intercept SysError calls }
  1448.         UnpatchTrap(pSysErrPatch);
  1449.         END;
  1450.     END;
  1451.  
  1452. {--------------------------------------------------------------------------------------------------}
  1453. {$S MADebugger}
  1454.  
  1455. PROCEDURE JTOffProc(A5JTOffset: UNIV INTEGER;
  1456.                     VAR s: UNIV DisAsmStr80);
  1457.  
  1458.     CONST
  1459.         kUnloaded            = $3F3C;
  1460.  
  1461.     VAR
  1462.         aName:                MAName;
  1463.         pc:                 Longint;
  1464.  
  1465.     BEGIN
  1466.     pc := Longint(GetA5) + A5JTOffset;
  1467.     IF IntegerPtr(pc)^ <> kUnloaded THEN
  1468.         BEGIN
  1469.         GetMethodName(ord(@pc), aName);
  1470.         s := aName;
  1471.         END
  1472.     ELSE
  1473.         s := '';
  1474.     END;
  1475.  
  1476. {$EndC}
  1477.  
  1478. {--------------------------------------------------------------------------------------------------}
  1479. {$S MADebugger}
  1480.  
  1481. FUNCTION IsUserBreak: BOOLEAN;
  1482.  
  1483.     VAR
  1484.         aKeyMap:            KeyMap;
  1485.         oldState:            INTEGER;
  1486.  
  1487.     BEGIN
  1488.     oldState := IntegerPtr(JournalFlag)^;
  1489.     IntegerPtr(JournalFlag)^ := 0;                        { turn off journaling }
  1490.     GetKeys(aKeyMap);
  1491.     IntegerPtr(JournalFlag)^ := oldState;
  1492.     IsUserBreak := aKeyMap[55] & aKeyMap[56] & aKeyMap[58] & (NOT qDebug | pUDebugInitialized);
  1493.     END;
  1494.  
  1495. {$IFC qDebug}
  1496. {--------------------------------------------------------------------------------------------------}
  1497. {$S MADebugger}
  1498.  
  1499. PROCEDURE stdHelpProc;
  1500.  
  1501.     BEGIN
  1502.     WriteLn;
  1503.     WriteLn('Reply with one of the letters in the brackets');
  1504.     WriteLn;
  1505.     END;
  1506.  
  1507. {--------------------------------------------------------------------------------------------------}
  1508. {$S MADebugger}
  1509.  
  1510. FUNCTION GetPromptedChar(prompt: StringPtr;
  1511.                          validChars: StringPtr;
  1512.                          PROCEDURE helpProc): CHAR;
  1513.  
  1514.     VAR
  1515.         ch:                 CHAR;
  1516.         done:                BOOLEAN;
  1517.         index:                INTEGER;
  1518.  
  1519.     PROCEDURE WriteThePrompt;
  1520.  
  1521.         BEGIN
  1522.         Write(prompt^); Write(' ['); Write(validChars^); Write(kHelpRequest);
  1523.         Write(']: ');
  1524.         END;
  1525.  
  1526.     BEGIN
  1527.     WriteThePrompt;
  1528.     REPEAT
  1529.         pDebugView.RevealInsertionPoint;
  1530.         ch := UprChar(DebugReadCh);
  1531.         CASE ch OF
  1532.             kHelpRequest, chHelp:
  1533.                 BEGIN
  1534.                 helpProc;
  1535.                 WriteThePrompt;
  1536.                 done := FALSE
  1537.                 END;
  1538.             chReturn:
  1539.                 BEGIN
  1540.                 WriteLn;
  1541.                 done := true;
  1542.                 END;
  1543.             OTHERWISE
  1544.                 BEGIN
  1545.                 FOR index := 1 TO length(validChars^) DO
  1546.                     IF ch = UprChar(validChars^[index]) THEN
  1547.                         BEGIN
  1548.                         WriteLn(ch);
  1549.                         done := true;
  1550.                         LEAVE;
  1551.                         END;
  1552.                 IF index > length(validChars^) THEN
  1553.                     gApplication.Beep(30);                { 1/2 second }
  1554.                 END;
  1555.         END;
  1556.     UNTIL done;
  1557.     GetPromptedChar := ch;
  1558.     END;
  1559.  
  1560. {--------------------------------------------------------------------------------------------------}
  1561. {$S MADebugger}
  1562.  
  1563. FUNCTION GetPromptedString(prompt: StringPtr;
  1564.                            PROCEDURE helpProc): Str255;
  1565.  
  1566.     VAR
  1567.         returnStr:            Str255;
  1568.         done:                BOOLEAN;
  1569.  
  1570.     BEGIN
  1571.     Write(prompt^);
  1572.     returnStr := '';
  1573.     REPEAT
  1574.         pDebugView.RevealInsertionPoint;
  1575.         ch := DebugReadCh;
  1576.         CASE ch OF
  1577.             chHelp:
  1578.                 BEGIN
  1579.                 WriteLn;
  1580.                 helpProc;
  1581.                 Write(prompt^);
  1582.                 done := FALSE
  1583.                 END;
  1584.             chBackspace:
  1585.                 BEGIN
  1586.                 IF length(returnStr) > 0 THEN
  1587.                     BEGIN
  1588.                     Write(ch);
  1589.                     returnStr[0] := CHR(max(length(returnStr) - 1, 0));
  1590.                     END;
  1591.                 done := FALSE
  1592.                 END;
  1593.             chReturn:
  1594.                 BEGIN
  1595.                 Write(ch);
  1596.                 IF returnStr = kHelpRequest THEN
  1597.                     BEGIN
  1598.                     returnStr := '';
  1599.                     helpProc;
  1600.                     Write(prompt^);
  1601.                     done := FALSE
  1602.                     END
  1603.                 ELSE
  1604.                     done := true;
  1605.                 END;
  1606.             OTHERWISE
  1607.                 BEGIN
  1608.                 Write(ch);
  1609.                 returnStr := concat(returnStr, ch);
  1610.                 done := FALSE;
  1611.                 END;
  1612.         END;
  1613.     UNTIL done;
  1614.     GetPromptedString := returnStr;
  1615.     END;
  1616.  
  1617. {--------------------------------------------------------------------------------------------------}
  1618. {$S MADebugger}
  1619.  
  1620. FUNCTION GetFreeMastersCount: Longint;
  1621.  
  1622.     VAR
  1623.         zone:                THZ;
  1624.         pL:                 LongIntPtr;
  1625.         mpCnt:                Longint;
  1626.  
  1627.     BEGIN
  1628.     zone := ApplicZone;
  1629.     pL := LongIntPtr(zone^.hFstFree);
  1630.     mpCnt := 0;
  1631.     WHILE pL <> NIL DO
  1632.         BEGIN
  1633.         mpCnt := mpCnt + 1;
  1634.         pL := LongIntPtr(pL^);
  1635.         END;
  1636.     GetFreeMastersCount := mpCnt;
  1637.     END;
  1638.  
  1639. {--------------------------------------------------------------------------------------------------}
  1640. {$S MADebugger}
  1641.  
  1642. PROCEDURE CheckFreeMasters;
  1643.  
  1644.     VAR
  1645.         mp:                 Longint;
  1646.  
  1647.     BEGIN
  1648.     IF pMasters > 0 THEN                                { we computed # masters before }
  1649.         BEGIN
  1650.         mp := GetFreeMastersCount;
  1651.         IF pMasters <> mp THEN
  1652.             BEGIN
  1653.             WriteLn('pMasters: ', pMasters, '  current masters: ', mp);
  1654.             IF gMemMgtBreak THEN
  1655.                 gSingleStep := true;
  1656.             END;
  1657.         END;
  1658.  
  1659.     pMasters := GetFreeMastersCount
  1660.     END;
  1661.  
  1662. {--------------------------------------------------------------------------------------------------}
  1663. {$S MADebugger}
  1664.  
  1665. VAR
  1666.     aStaticString:        Str255;
  1667.  
  1668. PROCEDURE DebugWriteLn(textBuf: Ptr;
  1669.                        byteCount: INTEGER);
  1670.  
  1671.     VAR
  1672.         oldpCanEnterWriteLn: BOOLEAN;
  1673.  
  1674.     PROCEDURE WhatToDo;
  1675.  
  1676.         BEGIN
  1677.         IF fCaptureProc <> NIL THEN
  1678.             CallCapture(textBuf, byteCount, fCaptureProc);
  1679.  
  1680.         IF pDebugView <> NIL THEN
  1681.             pDebugView.AddText(textBuf, byteCount)        { send it to the current transcript window }
  1682.         END;
  1683.  
  1684.     BEGIN
  1685.     oldpCanEnterWriteLn := pCanEnterWriteLn;
  1686.     pCanEnterWriteLn := FALSE;
  1687.  
  1688.     IF NOT oldpCanEnterWriteLn THEN                     { Not re-entrant but at least give user a
  1689.                                                          fighting chance }
  1690.         BEGIN
  1691.         aStaticString[0] := CHR(Min(255, byteCount));
  1692.         BlockMove(textBuf, @aStaticString[1], length(aStaticString));
  1693.         DebugStr(concat('Re-entering DebugWriteLn: ', aStaticString));
  1694.         END;
  1695.  
  1696.     WithHideFromMacAppDo(WhatToDo, PartialHide);
  1697.       pCanEnterWriteLn := oldpCanEnterWriteLn;
  1698.  
  1699.     END;
  1700.  
  1701. {--------------------------------------------------------------------------------------------------}
  1702. {$S MADebugger}
  1703.  
  1704. PROCEDURE InstallWriteLnHook;
  1705.  
  1706.     CONST
  1707.         kConsoleName        = 'Dev:Console';
  1708.         _CODEV                = 1;                        { console device number }
  1709.  
  1710.     VAR
  1711.         slot:                Longint;
  1712.         oldProc:            ProcPtr;
  1713.  
  1714.     BEGIN
  1715.     pFileName := kConsoleName;
  1716.     slot := _addDevHandler(_CODEV, 0, ord(@DevFAccess), ord(@DevClose), ord(@DevRead),
  1717.                            ord(@DevWrite), ord(@DevIoctl));
  1718.     PLsetvbuf(output, NIL, _IOLBF, 128);
  1719.     oldProc := SetGetProc(@DebugReadLn);
  1720.     oldProc := SetPutProc(@DebugWriteLn);
  1721.     END;
  1722.  
  1723. {--------------------------------------------------------------------------------------------------}
  1724. {$S MAInit}
  1725.  
  1726. PROCEDURE InitUDebug(segTable, nonRes: Handle;
  1727.                      enterProc, inspectProc, symbolProc: Ptr);
  1728. { essential initialization (segTable, nonRes left in for compatibility (2.0) }
  1729.  
  1730.     CONST
  1731.         kDebugHeight        = 100;
  1732.         kVMargin            = 4;
  1733.         kHMargin            = 4;
  1734.  
  1735.     TYPE
  1736.         dbugParams            = RECORD                    { Format of 'dbug' resource }
  1737.             boundsRect:         Rect;                    { Rect of debugging window }
  1738.             fontNumber:         INTEGER;                { Font rsrc ID }
  1739.             fontSize:            INTEGER;                { Font size }
  1740.             numLines:            INTEGER;                { Number of lines }
  1741.             lineWidth:            INTEGER;                { Line width }
  1742.             openInitially:        BOOLEAN;                { Open Initially }
  1743.             title:                Str255;                 { Actually, variable length }
  1744.             END;
  1745.         dbugParamsPtr        = ^dbugParams;
  1746.         dbugParamsHandle    = ^dbugParamsPtr;
  1747.  
  1748.     VAR
  1749.         aTranscriptView:    TTranscriptView;
  1750.         wasAddNewObjectsToInspector: BOOLEAN;
  1751.         wasTrcEnable:        BOOLEAN;
  1752.         dParams:            Handle;
  1753.  
  1754.         addr:                Longint;
  1755.         i:                    INTEGER;
  1756.         err:                OSErr;
  1757.         vhs:                VHSelect;
  1758.         zoomedOutSize:        Point;
  1759.         aDebugParams:        dbugParams;
  1760.         aTextStyle:         TextStyle;
  1761.         Errs:                Handle;
  1762.  
  1763.     BEGIN
  1764.     pCanEnterWriteLn := true;
  1765.     pMadeNMRequest := FALSE;
  1766.     IF YouAreWarned THEN                                { for testing }
  1767.         pInterceptExceptionVectors := FALSE
  1768.     ELSE
  1769.         pInterceptExceptionVectors := true;
  1770.  
  1771.     {$IFC NOT qDebugTheDebugger}
  1772.     wasAddNewObjectsToInspector := AddNewObjectsToInspector(FALSE);
  1773.     {$ENDC}
  1774.  
  1775.     New(pDebugApplication);
  1776.  
  1777.     {$IFC NOT qDebugTheDebugger}
  1778.     IF AddNewObjectsToInspector(wasAddNewObjectsToInspector) THEN;
  1779.     {$ENDC}
  1780.  
  1781.     FailNil(pDebugApplication);
  1782.     pDebugApplication.IDebugApplication;
  1783.  
  1784.     { T R I C K   N O T E }
  1785.     { This will allow debugger window operations (resizing, etc.) that require a gApplication
  1786.     to succeed before the real application is available.  When the real application's IApplication
  1787.     method is called the global: gApplication will be replaced with a reference to it. }
  1788.     gApplication := pDebugApplication;
  1789.     gTarget := pDebugApplication;
  1790.  
  1791.     pSavedState.SaveVisRgn := NIL;
  1792.     pSavedState.SaveVisRgn := MakeNewRgn;
  1793.     FailNil(pSavedState.SaveVisRgn);
  1794.  
  1795.     pSavedState.gCursorRgn := NIL;
  1796.     pSavedState.gCursorRgn := MakeNewRgn;
  1797.     FailNil(pSavedState.gCursorRgn);
  1798.  
  1799.     pTP2PerfGlobals := NIL;
  1800.  
  1801.     pTraceToggle := FALSE;
  1802.     gSingleStep := FALSE;
  1803.     pBreakCount := 0;
  1804.     pTraceEnabled := FALSE;
  1805.     gTracing := FALSE;
  1806.     gReportNext := FALSE;
  1807.     gReportInfo := '';
  1808.     gReportTime := FALSE;
  1809.     pQuietOutput := FALSE;
  1810.  
  1811.     pMasters := - 1;
  1812.  
  1813.     pFlagsInUse := 0;
  1814.     pSymsInUse := 0;
  1815.  
  1816.     gMaxStackDepth := - 1;
  1817.     pBreakStack := $7FFFFFFF;
  1818.     pStepOverStackSize := 0;
  1819.     pBrProcStack := $7FFFFFFF;
  1820.     gMaxLockedRsrc := 0;
  1821.  
  1822.     pAddTextFocusRec.Clip := NIL;
  1823.     pAddTextFocusRec.Clip := MakeNewRgn;
  1824.     pAddTextFocusRec.FocusedView := NIL;
  1825.     pAddTextFocusRec.Org := gZeroPt;
  1826.     pAddTextFocusRec.LongOffset := gZeroVPt;
  1827.     pAddTextFocusRec.Port := gWorkPort;
  1828.     pAddTextFocusRec.printing := FALSE;
  1829.     pAddTextFocusRec.drawingPictScrap := FALSE;
  1830.  
  1831.     pSavedState.pFocusRec.Clip := NIL;
  1832.     pSavedState.pFocusRec.Clip := MakeNewRgn;
  1833.  
  1834.     pSavedState.gBusyTempRgn := FALSE;
  1835.     pSavedState.gUsedBy := '';
  1836.     pSavedState.gTempRgn := NIL;
  1837.     pSavedState.gTempRgn := MakeNewRgn;
  1838.     pDisciplineMethodCalls := true;                     { matches default in uobject }
  1839.  
  1840.     pFullyHiddenFromMacapp := FALSE;
  1841.  
  1842.     pEnterProc := enterProc;
  1843.     pInspectProc := inspectProc;
  1844.     pSymbolProc := symbolProc;
  1845.  
  1846.     FOR i := 0 TO kRecent DO
  1847.         BEGIN
  1848.         pRecentPC[i].thePC := 0;
  1849.         pRecentPC[i].theZT := tSysError;
  1850.         END;
  1851.     pRecentIndex := 0;
  1852.  
  1853.     fCaptureProc := NIL;
  1854.     pReserve := NewPermHandle(kReserve);                { Reserve some space in case of SysErr }
  1855.     FailNil(pReserve);
  1856.  
  1857.     InstallInterceptors(true);
  1858.  
  1859.     {$IFC NOT qDebugTheDebugger}
  1860.     wasAddNewObjectsToInspector := AddNewObjectsToInspector(FALSE);
  1861.     {$ENDC}
  1862.  
  1863.     dParams := GetResource('dbug', kDebugParamsID);
  1864.     IF dParams <> NIL THEN
  1865.         BEGIN
  1866.         aDebugParams := dbugParamsHandle(dParams)^^;
  1867.         ReleaseResource(dParams);                        { asta la vista }
  1868.         WITH aDebugParams DO
  1869.             BEGIN
  1870.             IF EqualRect(boundsRect, gZeroRect) THEN
  1871.                 BEGIN
  1872.                 boundsRect := screenbits.bounds;
  1873.                 InsetRect(boundsRect, 5, 5);
  1874.                 boundsRect.top := boundsRect.bottom - kDebugHeight;
  1875.                 END
  1876.             END
  1877.         END
  1878.     ELSE
  1879.         WITH aDebugParams DO
  1880.             BEGIN
  1881.             boundsRect := screenbits.bounds;
  1882.             InsetRect(boundsRect, 5, 5);
  1883.             boundsRect.top := boundsRect.bottom - kDebugHeight;
  1884.  
  1885.             fontNumber := kDebugFont;
  1886.             fontSize := kDebugSize;
  1887.             numLines := 120;
  1888.             lineWidth := 100;
  1889.             openInitially := FALSE;
  1890.             title := '';
  1891.             END;
  1892.  
  1893.     IF qTemplateViews THEN
  1894.         BEGIN
  1895.         pDebugWindow := NewTemplateWindow(kDebugWindowType, NIL);
  1896.         pDebugView := TTranscriptView(pDebugWindow.FindSubView('trns'));
  1897.         END
  1898.     ELSE
  1899.         BEGIN
  1900.         New(aTranscriptView);
  1901.         FailNil(aTranscriptView);
  1902.         WITH aDebugParams DO
  1903.             aTranscriptView.ITranscriptView(NIL, fontNumber, fontSize, numLines, lineWidth);
  1904.  
  1905.         pDebugView := aTranscriptView;
  1906.  
  1907.         pDebugWindow := NewSimpleWindow(kDebugWindowType, kWantHScrollBar, kWantVScrollBar, NIL,
  1908.                                         pDebugView);
  1909.  
  1910.         END;
  1911.  
  1912.     pDebugView.fHelpProc := @MainHelpProc;
  1913.     WITH aDebugParams DO
  1914.         BEGIN
  1915.         IF title <> '' THEN
  1916.             pDebugWindow.SetTitle(title);
  1917.         pDebugWindow.Locate(boundsRect.left, boundsRect.top, kDontInvalidate);
  1918.         pDebugWindow.Resize(MinMax(kSBarSize * 4, boundsRect.right - boundsRect.left,
  1919.                                    max(pDebugView.fSize.h + kSBarSize, boundsRect.right -
  1920.                                    boundsRect.left)), MinMax(kSBarSize * 4, boundsRect.bottom -
  1921.                                                              boundsRect.top,
  1922.                                                              max(pDebugView.fSize.v + kSBarSize,
  1923.                                                              boundsRect.bottom - boundsRect.top)),
  1924.                             kDontInvalidate);
  1925.         SetTextStyle(aTextStyle, fontNumber, [], fontSize, gRGBBlack);
  1926.         pDebugView.InstallTextStyle(aTextStyle);
  1927.         {$Push} {$H-}
  1928.         zoomedOutSize := VPtToPt(pDebugView.fSize);
  1929.         {$Pop}
  1930.         WITH zoomedOutSize DO
  1931.             BEGIN
  1932.             v := (2 * kVMargin) + (pDebugView.fFontHeight * (pDebugView.fRows));
  1933.             v := max(kSBarSize * 4, v + kSBarSize);
  1934.             h := max(kSBarSize * 4, h + kSBarSize);
  1935.             END;
  1936.  
  1937.         pDebugWindow.SetResizeLimits(gStdWSizeRect.topLeft, zoomedOutSize);
  1938.         pDebugWindow.ForceOnScreen;
  1939.         IF openInitially THEN
  1940.             pDebugWindow.Open;
  1941.         pDebugWindow.Update;
  1942.         END;
  1943.  
  1944.     gApplication.DeleteFreeWindow(pDebugWindow);        { so we don't show }
  1945.  
  1946.     {$IFC NOT qDebugTheDebugger}
  1947.     IF AddNewObjectsToInspector(wasAddNewObjectsToInspector) THEN;
  1948.     {$ENDC}
  1949.  
  1950.     {$IFC IncludeDisassembler}
  1951.     { Init Ira's disassembler }
  1952.     InitLookup(NIL, @JTOffProc, @LookupTrapName, NIL, NIL);
  1953.     {$EndC}
  1954.  
  1955.     VBLInstall;
  1956.  
  1957.     DebugGlobalHandle(@pSavedState.gTarget, NIL, AtMAName('gTarget'));
  1958.     DebugGlobalHandle(@pSavedState.gApplication, NIL, AtMAName('gApplication'));
  1959.     DebugGlobalHandle(@gDocList, NIL, AtMAName('gDocList'));
  1960.     DebugGlobalHandle(@gFreeWindowList, NIL, AtMAName('gFreeWindowList'));
  1961.     DebugGlobalHandle(@gClipView, NIL, AtMAName('gClipView'));
  1962.     DebugGlobalHandle(@gClipUndoView, NIL, AtMAName('gClipUndoView'));
  1963.     DebugGlobalHandle(@gPrintHandler, NIL, AtMAName('gPrintHandler'));
  1964.     DebugGlobalHandle(@pSavedState.pFocusRec.FocusedView, NIL, AtMAName('gFocusedView'));
  1965.  
  1966.     DebugGlobalHandle(NIL, @DebugGetLastCommand, AtMAName('GetLastCommand'));
  1967.     DebugGlobalHandle(NIL, @DebugGetActiveWindow, AtMAName('GetActiveWindow'));
  1968.     DebugGlobalHandle(NIL, @DebugGetActiveDocument, AtMAName('GetActiveDocument'));
  1969.  
  1970.     DebugFlag(@pSavedState.gIntenseDebugging, 'I', NIL, AtStr('Intense debugging'));
  1971.     DebugFlag(@gMemMgtBreak, 'B', NIL, AtStr('Memory management break'));
  1972.     DebugFlag(@gMastReport, 'M', NIL, AtStr('Report # masters'));
  1973.     DebugFlag(@gSegReport, 'S', NIL, AtStr('Report segment load'));
  1974.     DebugFlag(@gUnloadAllSegs, 'U', NIL, AtStr('Unload segments'));
  1975.     DebugFlag(@gExperimenting, 'X', NIL, AtStr('Experimenting'));
  1976.     DebugFlag(@gAskFailure, 'F', NIL, AtStr('Ask about failures'));
  1977.     DebugFlag(@gReportEvt, 'E', NIL, AtStr('Report events'));
  1978.     DebugFlag(@gAskAboutAlloc, 'A', NIL, AtStr('Ask about allocations'));
  1979.     DebugFlag(@gRsrcReport, 'R', NIL, AtStr('Report resource usage'));
  1980.     DebugFlag(@gReportMenuChoices, 'C', NIL, AtStr('Report menu commands'));
  1981.     DebugFlag(@pSavedState.gDebugPrinting, 'P', NIL, AtStr('Printing debug'));
  1982.     DebugFlag(@pDisciplineMethodCalls, 'D', @DisciplineMethodCalls,
  1983.               AtStr('Discipline method calls'));
  1984.     DebugFlag(@gAssumeFocused, 'V', NIL, AtStr('Do "AssumeFocused" preconditioning'));
  1985.  
  1986.     {$IFC qExperimentalAndUnsupported}
  1987.     DebugFlag(@gEnableDoubleBuffering, 'G', NIL, AtStr('Enable double buffering of views'));
  1988.     {$EndC}
  1989.  
  1990.     { Make sure the error strings are always available by loading them and but not
  1991.     letting them be purgeable }
  1992.     Errs := GetResource('STR#', 252);
  1993.     FailNILResource(Errs);
  1994.     HNoPurge(Errs);
  1995.  
  1996.     IF qTemplateViews THEN
  1997.         BEGIN
  1998.         { Suppress Linker dead stripping of these }
  1999.         IF gDeadStripSuppression THEN
  2000.             IF Member(TObject(NIL), TTranscriptView) THEN;
  2001.         END;
  2002.  
  2003.     { LAST THING ON INIT: install the console interceptor }
  2004.     InstallWriteLnHook;
  2005.  
  2006.     pUDebugInitialized := true;
  2007.     pCanEnterDebugger := true;
  2008.  
  2009.     END;
  2010.  
  2011. {--------------------------------------------------------------------------------------------------}
  2012. {$S MADebugger}
  2013.  
  2014. PROCEDURE DebugTerminate;
  2015.  
  2016.     BEGIN
  2017.     IF pUDebugInitialized THEN
  2018.         BEGIN
  2019.         VBLRemove;
  2020.  
  2021.         IF DebugRedirect(0, NIL) <> noErr THEN;         { (discard result) close redirect file }
  2022.  
  2023.         {$IFC qPerform}
  2024.         { Make sure the performance tools are shut down if they are initialized }
  2025.         IF pTP2PerfGlobals <> NIL THEN
  2026.             BEGIN
  2027.             TermPerf(pTP2PerfGlobals);
  2028.             pTP2PerfGlobals := NIL;
  2029.             END;
  2030.         {$ENDC}
  2031.  
  2032.         InstallInterceptors(FALSE);
  2033.  
  2034.         { Guarantee we can't be re-entered }
  2035.         pUDebugInitialized := FALSE;
  2036.         pCanEnterDebugger := FALSE;
  2037.  
  2038.         END;
  2039.     END;
  2040. {--------------------------------------------------------------------------------------------------}
  2041. {$S MADebugger}
  2042.  
  2043. PROCEDURE DebugFlag(flagAddr: BooleanPtr;
  2044.                     flagChar: CHAR;
  2045.                     theActionProc: ProcPtr;             {CONST}
  2046.                     flagDesc: StringPtr);
  2047. { Register a BOOLEAN flag for the X debugger command;
  2048. flagAddr should be the address of the flag;
  2049. theActionProc should be a procPtr for a proc to be called to change the flag (optional).
  2050. flagChar should be the character to use in the debugger to toggle the flag;
  2051. desc should be a short description of the flag.
  2052. No checking is done for duplicate flagChars. }
  2053.  
  2054.     BEGIN
  2055.     IF pFlagsInUse < kMaxFlags THEN
  2056.         BEGIN
  2057.         pFlagsInUse := pFlagsInUse + 1;
  2058.         WITH pFlagTable[pFlagsInUse] DO
  2059.             BEGIN
  2060.             addr := flagAddr;
  2061.             ch := UprChar(flagChar);
  2062.             actionProc := theActionProc;
  2063.             desc := NewString(flagDesc^);
  2064.             FailNil(desc);
  2065.             END;
  2066.         END;
  2067.     END;
  2068.  
  2069. {--------------------------------------------------------------------------------------------------}
  2070. {$S MADebugger}
  2071.  
  2072. PROCEDURE DebugGlobalHandle(globAddr: Ptr;
  2073.                             theActionProc: ProcPtr;     {CONST}
  2074.                             globSym: MANamePtr);
  2075. { Register a symbol name of a global variable that contains a handle;
  2076. Case does not matter.  The global variable should contain a Handle.
  2077. The Action proc is a Function to be called to derive the handle if necessary. }
  2078.  
  2079.     BEGIN
  2080.     IF pSymsInUse < kMaxSyms THEN
  2081.         BEGIN
  2082.         pSymsInUse := pSymsInUse + 1;
  2083.         WITH pSymTable[pSymsInUse] DO
  2084.             BEGIN
  2085.             addr := globAddr;
  2086.             actionProc := theActionProc;
  2087.             sym := globSym^;
  2088.  
  2089.             END;
  2090.         END;
  2091.     END;
  2092.  
  2093. {--------------------------------------------------------------------------------------------------}
  2094. {$S MADebugger}
  2095.  
  2096. FUNCTION GetPromptedNames(prompt: StringPtr;
  2097.                           VAR className, procName: MAName): BOOLEAN;
  2098.  
  2099.     VAR
  2100.         ch:                 CHAR;
  2101.         len:                INTEGER;
  2102.         s:                    Str255;
  2103.         i:                    INTEGER;
  2104.  
  2105.     PROCEDURE helpProc;
  2106.  
  2107.         BEGIN
  2108.         WriteLn;
  2109.         WriteLn('Please supply a ClassName.MethodName or MethodName or ProcName');
  2110.         WriteLn;
  2111.         END;
  2112.  
  2113.     BEGIN
  2114.     GetPromptedNames := FALSE;
  2115.  
  2116.     className := '';
  2117.     procName := '';
  2118.     len := 0;
  2119.  
  2120.     s := GetPromptedString(prompt, helpProc);
  2121.  
  2122.     FOR i := 1 TO length(s) DO
  2123.         BEGIN
  2124.         ch := UprChar(s[i]);
  2125.  
  2126.         IF ch IN ['A'..'Z', '0'..'9', '_', '%'] THEN
  2127.             BEGIN
  2128.             GetPromptedNames := true;
  2129.             len := len + 1;
  2130.             procName[len] := ch;
  2131.             procName[0] := CHR(len);
  2132.             END
  2133.         ELSE IF ch = '.' THEN
  2134.             BEGIN
  2135.             className := procName;
  2136.             procName := '';
  2137.             len := 0;
  2138.             END
  2139.         ELSE IF ch <> ' ' THEN
  2140.             BEGIN
  2141.             GetPromptedNames := FALSE;
  2142.             WriteLn(kDontKnow);
  2143.             Exit(GetPromptedNames);
  2144.             END;
  2145.         END;
  2146.     END;
  2147.  
  2148. {--------------------------------------------------------------------------------------------------}
  2149. {$S MADebugger}
  2150.  
  2151. FUNCTION GetPromptedValue(prompt: StringPtr;
  2152.                           VAR asDecimal, asHex: Longint;
  2153.                           symbolOK: BOOLEAN;
  2154.                           VAR gotSymbol: BOOLEAN): BOOLEAN;
  2155.  { returns TRUE iff a valid number is typed;
  2156.   if it returns FALSE but the parameters are 0, then the user typed only a return;
  2157.  
  2158.   if symbolOK is TRUE then a symbol is allowed, and gotSymbol will indicate if
  2159.   a symbol was typed }
  2160.  
  2161.     VAR
  2162.         ch:                 CHAR;
  2163.         digit:                INTEGER;
  2164.         anEvent:            EventRecord;
  2165.         s:                    Str255;
  2166.         i:                    INTEGER;
  2167.         sym:                Str255;
  2168.         done:                BOOLEAN;
  2169.         symbolTableSym:     Str255;
  2170.         gotNegation:        BOOLEAN;
  2171.  
  2172.     PROCEDURE helpProc;
  2173.  
  2174.         VAR
  2175.             i:                    INTEGER;
  2176.  
  2177.         BEGIN
  2178.         WriteLn;
  2179.         Write('Please supply a valid number');
  2180.         IF NOT symbolOK THEN
  2181.             WriteLn('.')
  2182.         ELSE
  2183.             BEGIN
  2184.             Write(' or one of the following symbols:');
  2185.             sym := kHelpRequest;
  2186.             asDecimal := CallSymbolLookup(sym, pSymbolProc);
  2187.             WriteLn;
  2188.  
  2189.             FOR i := 1 TO pSymsInUse DO
  2190.                 Write(pSymTable[i].sym, ' ');
  2191.             WriteLn;
  2192.             END;
  2193.         END;
  2194.  
  2195.     BEGIN
  2196.     asDecimal := 0;
  2197.     asHex := 0;
  2198.     gotSymbol := FALSE;
  2199.  
  2200.     s := GetPromptedString(prompt, helpProc);
  2201.     UprString(s, FALSE);
  2202.  
  2203.     IF s = '' THEN
  2204.         GetPromptedValue := FALSE
  2205.     ELSE
  2206.         BEGIN
  2207.         GetPromptedValue := true;
  2208.  
  2209.         IF symbolOK & ((s[1] = '''') | NOT (s[1] IN ['-', '0'..'9', 'A'..'F'])) THEN
  2210.             BEGIN
  2211.             gotSymbol := true;
  2212.  
  2213.             IF s[1] = '''' THEN
  2214.                 Delete(s, 1, 1);
  2215.  
  2216.             sym := s;
  2217.  
  2218.             asDecimal := CallSymbolLookup(sym, pSymbolProc);
  2219.  
  2220.             IF asDecimal = - 1 THEN                     { search local symbol table }
  2221.                 BEGIN
  2222.                 i := 1;
  2223.                 symbolTableSym := pSymTable[i].sym;
  2224.                 UprStr255(symbolTableSym);
  2225.                 WHILE (i <= pSymsInUse) & (symbolTableSym <> sym) DO
  2226.                     BEGIN
  2227.                     i := i + 1;
  2228.                     IF (i <= pSymsInUse) THEN
  2229.                         BEGIN
  2230.                         symbolTableSym := pSymTable[i].sym;
  2231.                         UprStr255(symbolTableSym);
  2232.                         END;
  2233.                     END;
  2234.  
  2235.                 IF i <= pSymsInUse THEN
  2236.                     BEGIN
  2237.                     IF pSymTable[i].addr = NIL THEN
  2238.                         asDecimal := Longint(CallSymActionProc(pSymTable[i].actionProc))
  2239.                     ELSE
  2240.                         asDecimal := LongIntPtr(pSymTable[i].addr)^;
  2241.                     END;
  2242.                 END;
  2243.             asHex := asDecimal;
  2244.  
  2245.             IF asHex = - 1 THEN
  2246.                 BEGIN
  2247.                 WriteLn(kDontKnow);
  2248.                 GetPromptedValue := FALSE;
  2249.                 END;
  2250.             END
  2251.         ELSE
  2252.             BEGIN
  2253.             gotNegation := FALSE;
  2254.             FOR i := 1 TO length(s) DO
  2255.                 BEGIN
  2256.                 ch := s[i];
  2257.  
  2258.                 digit := - 1;
  2259.                 IF ch IN ['0'..'9'] THEN
  2260.                     digit := ord(ch) - ord('0')
  2261.                 ELSE IF ch IN ['-'] THEN
  2262.                     gotNegation := true
  2263.                 ELSE IF ch IN ['A'..'F'] THEN
  2264.                     BEGIN
  2265.                     digit := 10 + ord(ch) - ord('A');
  2266.                     asDecimal := - 1;
  2267.                     END
  2268.                 ELSE
  2269.                     BEGIN
  2270.                     asDecimal := - 1;
  2271.                     asHex := - 1;
  2272.                     WriteLn(kDontKnow);
  2273.                     GetPromptedValue := FALSE;
  2274.                     Exit(GetPromptedValue)
  2275.                     END;
  2276.  
  2277.                 IF digit >= 0 THEN
  2278.                     BEGIN
  2279.                     IF asDecimal >= 0 THEN
  2280.                         asDecimal := 10 * asDecimal + digit;
  2281.                     IF asHex >= 0 THEN
  2282.                         asHex := 16 * asHex + digit;
  2283.                     END;
  2284.                 END;
  2285.             IF gotNegation THEN
  2286.                 BEGIN
  2287.                 IF (asDecimal >= 0) THEN
  2288.                     asDecimal := - asDecimal;
  2289.                 IF asHex >= 0 THEN
  2290.                     asHex := - asHex;
  2291.                 END;
  2292.             END;
  2293.         END;
  2294.     END;
  2295.  
  2296. {--------------------------------------------------------------------------------------------------}
  2297. {$S MADebugger}
  2298.  
  2299. FUNCTION GetPromptedNumber(prompt: StringPtr;
  2300.                            VAR asDecimal, asHex: Longint): BOOLEAN; { returns TRUE iff a valid
  2301.                                                                      number is typed; if it returns
  2302.                                                                      FALSE but the parameters are
  2303.                                                                      0, then the user typed only a
  2304.                                                                      return }
  2305.  
  2306.     VAR
  2307.         symbol:             BOOLEAN;
  2308.  
  2309.     BEGIN
  2310.     GetPromptedNumber := GetPromptedValue(prompt, asDecimal, asHex, FALSE, symbol);
  2311.     END;
  2312.  
  2313. {--------------------------------------------------------------------------------------------------}
  2314. {$S MADebugger}
  2315.  
  2316. FUNCTION GetPromptedNumberWithDefault(prompt: StringPtr;
  2317.                                       default: INTEGER): INTEGER;
  2318. { Returns a number typed by the user.  Returns the default if a return is typed. }
  2319.  
  2320.     VAR
  2321.         s:                    Str255;
  2322.  
  2323.     BEGIN
  2324.     s := concat(ConcatNumber(concat(prompt^, ' [default = '), default), ']?:');
  2325.     IF GetPromptedNumber(@s, asDecimal, asHex) THEN
  2326.         GetPromptedNumberWithDefault := asDecimal
  2327.     ELSE
  2328.         GetPromptedNumberWithDefault := default;
  2329.     END;
  2330.  
  2331. {--------------------------------------------------------------------------------------------------}
  2332. {$S MADebugger}
  2333.  
  2334. FUNCTION GetPromptedStringWithDefault(prompt: StringPtr;
  2335.                                       default: StringPtr;
  2336.                                       PROCEDURE helpProc): Str255;
  2337. { Returns a string typed by the user.  Returns the default if a return is typed. }
  2338.  
  2339.     VAR
  2340.         s:                    Str255;
  2341.  
  2342.     BEGIN
  2343.     s := concat(prompt^, ' [default = ', default^, ']?:');
  2344.     s := GetPromptedString(@s, helpProc);
  2345.     IF s <> '' THEN
  2346.         GetPromptedStringWithDefault := s
  2347.     ELSE
  2348.         GetPromptedStringWithDefault := default^;
  2349.     END;
  2350.  
  2351. {--------------------------------------------------------------------------------------------------}
  2352. {$S MADebugger}
  2353. {$IFC IncludeDisassembler}
  2354. PROCEDURE ShowDisasmMemory(startAddress, numBytes: Longint);
  2355.  
  2356.     VAR
  2357.         idx:                INTEGER;
  2358.         BytesUsed:            INTEGER;
  2359.         opCode, Operand, Comment: DisAsmStr80;
  2360.  
  2361.     BEGIN
  2362.     WHILE numBytes > 0 DO
  2363.         BEGIN
  2364.         Disassembler(0, BytesUsed, startAddress, opCode, Operand, Comment, @Lookup);
  2365.         Write('    ');
  2366.         WritePtr(startAddress);
  2367.         Write(':  '); WriteLn(opCode, ' ', Operand, ' ', Comment);
  2368.         numBytes := numBytes - BytesUsed;
  2369.         startAddress := startAddress + BytesUsed;
  2370.         END;
  2371.     pMoreMem := startAddress;
  2372.     END;
  2373. {$EndC}
  2374.  
  2375. {$EndC}
  2376.  
  2377. {--------------------------------------------------------------------------------------------------}
  2378. {$S MADebugger}
  2379.  
  2380. PROCEDURE ShowMemory(startAddress, numBytes: Longint);
  2381.  
  2382.     VAR
  2383.         i:                    INTEGER;
  2384.         addr:                Longint;
  2385.         lines:                INTEGER;
  2386.         numeric:            STRING[40];
  2387.         ascii:                STRING[16];
  2388.         numPos:             INTEGER;
  2389.         ascPos:             INTEGER;
  2390.         decNumber:            Longint;
  2391.         chCode:             INTEGER;
  2392.         j:                    INTEGER;
  2393.  
  2394. {--------------------------------------------------------------------------------------------------}
  2395.  
  2396.     PROCEDURE BlankLine;
  2397.  
  2398.         CONST
  2399.             k8Spaces            = '        ';
  2400.  
  2401.         BEGIN
  2402.         ascii := concat(k8Spaces, k8Spaces);
  2403.         numeric := concat(ascii, ascii, k8Spaces);
  2404.         numPos := 0;
  2405.         ascPos := 0;
  2406.         END;
  2407.  
  2408. {--------------------------------------------------------------------------------------------------}
  2409.  
  2410.     PROCEDURE PrintLine;
  2411.  
  2412.         BEGIN
  2413.         WriteLn(numeric, '  ', ascii);
  2414.         END;
  2415.  
  2416.     BEGIN
  2417.     IF Odd(startAddress) THEN
  2418.         WriteLn('Odd Address')
  2419.     ELSE IF numBytes > 0 THEN
  2420.         BEGIN
  2421.         BlankLine;
  2422.  
  2423.         FOR i := 0 TO (numBytes - 1) DIV 2 DO
  2424.             BEGIN
  2425.             lines := 0;
  2426.             addr := startAddress + i + i;
  2427.  
  2428.             IF (i MOD 8) = 0 THEN
  2429.                 BEGIN
  2430.                 IF i > 0 THEN
  2431.                     BEGIN
  2432.                     PrintLine;
  2433.                     BlankLine;
  2434.                     lines := lines + 1;
  2435.                     END;
  2436.                 IF IsUserBreak | (lines > 20) THEN
  2437.                     BEGIN
  2438.                     WriteLn('More… [M]: ');
  2439.                     Exit(ShowMemory);
  2440.                     END;
  2441.                 Write('    ');
  2442.                 WritePtr(addr);
  2443.                 Write(':  ');
  2444.                 END;
  2445.  
  2446.             decNumber := IntegerPtr(addr)^;
  2447.             FOR j := 4 DOWNTO 1 DO
  2448.                 BEGIN
  2449.                 numeric[numPos + j] := kHexDigits[BAND(decNumber, 15) + 1];
  2450.                 decNumber := BSR(decNumber, 4);
  2451.                 END;
  2452.  
  2453.             decNumber := IntegerPtr(addr)^;
  2454.             FOR j := 2 DOWNTO 1 DO
  2455.                 BEGIN
  2456.                 chCode := BAND(decNumber, 255);
  2457.                 IF (chCode < $20) | (chCode > $D8) | (chCode = $7F) THEN { control, unassigned, or
  2458.                                                                           DEL }
  2459.                     chCode := ord('•');
  2460.                 ascii[ascPos + j] := CHR(chCode);
  2461.                 decNumber := BSR(decNumber, 8);
  2462.                 END;
  2463.  
  2464.             numPos := numPos + 5;
  2465.             ascPos := ascPos + 2;
  2466.  
  2467.             pMoreMem := addr + 2;
  2468.             END;
  2469.  
  2470.         PrintLine;
  2471.         END;
  2472.     END;
  2473.  
  2474. {$IFC qDebug}
  2475. {--------------------------------------------------------------------------------------------------}
  2476. {$S MADebugger}
  2477.  
  2478. FUNCTION ShowHierarchy(obj: TObject;
  2479.                        theClass: ObjClassID): Longint;
  2480.  
  2481.     VAR
  2482.         inspClass:            MAName;
  2483.         size:                Longint;
  2484.         super:                ObjClassID;
  2485.         shown:                INTEGER;
  2486.  
  2487.     BEGIN
  2488.     GetClassNameFromID(theClass, inspClass);            { srf 88.9.7 }
  2489.  
  2490.     IF inspClass = kInvalidObj THEN
  2491.         BEGIN
  2492.         size := GetHandleSize(Handle(obj));
  2493.         ShowMemory(ord(Handle(obj)^), size);
  2494.         END
  2495.     ELSE
  2496.         BEGIN
  2497.         size := GetClassSizeFromID(theClass);
  2498.         super := GetSuperClassID(theClass);
  2499.         IF super = kNilClass THEN                        { it is a root class, so skip class ptr }
  2500.             shown := sizeof(ObjClassID)
  2501.         ELSE
  2502.             shown := ShowHierarchy(obj, super);
  2503.         IF shown <= size THEN
  2504.             BEGIN
  2505.             GetClassNameFromID(theClass, inspClass);
  2506.             WriteLn(' ', inspClass);
  2507.             IF size > sizeof(ObjClassID) THEN            { don't show it if there are no fields }
  2508.                 ShowMemory(ord(Handle(obj)^) + shown, size - shown);
  2509.             END;
  2510.         END;
  2511.  
  2512.     ShowHierarchy := size;
  2513.     END;
  2514.  
  2515. {--------------------------------------------------------------------------------------------------}
  2516. {$S MADebugger}
  2517.  
  2518. PROCEDURE ShowFields(obj: TObject;
  2519.                      doInspect: BOOLEAN);
  2520.  
  2521.     VAR
  2522.         i:                    Longint;
  2523.         s:                    Longint;
  2524.         objName:            MAName;
  2525.  
  2526.     BEGIN
  2527.     IF ord(obj) = - 1 THEN
  2528.         Write('')
  2529.     ELSE IF ord(obj) = - 2 THEN
  2530.         WriteLn('  No object at that level (not a method).')
  2531.     ELSE IF VerboseIsObject(obj) THEN
  2532.         BEGIN
  2533.         IF doInspect THEN
  2534.             CallInspector(obj, pInspectProc)
  2535.         ELSE
  2536.             BEGIN
  2537.             i := ShowHierarchy(obj, GetClassID(obj));
  2538.             s := GetHandleSize(Handle(obj));
  2539.             IF i < s THEN
  2540.                 BEGIN
  2541.                 WriteLn('rest of handle:');
  2542.                 ShowMemory(ord(Handle(obj)^) + i, s - i);
  2543.                 END;
  2544.             END;
  2545.         END;
  2546.     END;
  2547.  
  2548. {--------------------------------------------------------------------------------------------------}
  2549. {$S MAUtilitiesRes}                                     { Shouldn't be unloaded }
  2550.  
  2551. PROCEDURE GetLevel(level: INTEGER;
  2552.                    topFrame: Longint;
  2553.                    VAR calleeFrame, itsFrame: Longint);
  2554.  
  2555.     VAR
  2556.         i:                    INTEGER;
  2557.  
  2558.     BEGIN
  2559.     calleeFrame := topFrame;
  2560.     IF Odd(calleeFrame) THEN
  2561.         itsFrame := calleeFrame
  2562.     ELSE
  2563.         BEGIN
  2564.         itsFrame := LongIntPtr(calleeFrame)^;
  2565.         FOR i := 1 TO level DO
  2566.             IF Odd(itsFrame) | (itsFrame >= Longint(GetA5)) | (itsFrame <= calleeFrame) THEN
  2567.                 itsFrame := calleeFrame
  2568.             ELSE
  2569.                 BEGIN
  2570.                 calleeFrame := itsFrame;
  2571.                 itsFrame := LongIntPtr(itsFrame)^;
  2572.                 END;
  2573.         END;
  2574.     END;
  2575.  
  2576. {--------------------------------------------------------------------------------------------------}
  2577. {$S MADebugger}
  2578.  
  2579. PROCEDURE GetFrameInfo(calleeFrame: Longint;
  2580.                        ppc: Longint;
  2581.                        VAR callerFrame: Longint;
  2582.                        VAR itsFrame: Longint;
  2583.                        VAR itsReceiver: TObject;
  2584.                        VAR className: MAName;
  2585.                        VAR procName: MAName;
  2586.                        VAR rcvrHandle: HexAddress;
  2587.                        VAR rcvrClass: MAName;
  2588.                        VAR theSegNum: INTEGER);
  2589.  
  2590.     VAR
  2591.         aStringPtr:         StringPtr;
  2592.  
  2593.     BEGIN
  2594.     GetProcName(ppc, className, procName);
  2595.     theSegNum := GetSegFromPC(ppc);
  2596.  
  2597.     GetLevel(1, calleeFrame, itsFrame, callerFrame);
  2598.  
  2599.     rcvrClass := kInvalidObj;
  2600.     IF Odd(itsFrame) | (length(className) = 0) THEN
  2601.         BEGIN
  2602.         Longint(itsReceiver) := - 2;
  2603.         rcvrHandle := kInvalidObj;
  2604.         END
  2605.     ELSE
  2606.         BEGIN
  2607.         Longint(itsReceiver) := LongIntPtr(itsFrame + 8)^;
  2608.         aStringPtr := StringPtr(@rcvrHandle);
  2609.         PointerToHex(itsReceiver, aStringPtr^, 8);
  2610.         IF IsObject(itsReceiver) THEN
  2611.             GetClassNameFromID(GetClassID(itsReceiver), rcvrClass);
  2612.         END;
  2613.     END;
  2614.  
  2615. {--------------------------------------------------------------------------------------------------}
  2616. {$S MADebugger}
  2617.  
  2618. FUNCTION GetRcvrAtLevel(level: INTEGER;
  2619.                         topFrame: Longint): TObject;
  2620.  
  2621.     VAR
  2622.         calleeFrame, callerFrame, itsFrame: Longint;
  2623.         receiver:            TObject;
  2624.         className, procName, rcvrClass: MAName;
  2625.         rcvrHandle:         HexAddress;
  2626.         dummy:                INTEGER;
  2627.  
  2628.     BEGIN
  2629.     itsFrame := topFrame;
  2630.     REPEAT
  2631.         calleeFrame := itsFrame;
  2632.         GetFrameInfo(calleeFrame, calleeFrame + 4, callerFrame, itsFrame, receiver, className,
  2633.                      procName, rcvrHandle, rcvrClass, dummy);
  2634.         level := level - 1;
  2635.     UNTIL (level < 0) | (calleeFrame = itsFrame);
  2636.     GetRcvrAtLevel := receiver;
  2637.     END;
  2638.  
  2639. {--------------------------------------------------------------------------------------------------}
  2640. {$S MADebugger}
  2641.  
  2642. PROCEDURE ShowLocals(level: INTEGER;
  2643.                      topFrame: Longint);
  2644.  
  2645.     VAR
  2646.         startAt, finishAt:    Longint;
  2647.         itsFrame, calleeFrame: Longint;
  2648.  
  2649.     BEGIN
  2650.     GetLevel(level, topFrame, calleeFrame, itsFrame);
  2651.     startAt := max(calleeFrame + 8, itsFrame - 80);
  2652.     finishAt := itsFrame;
  2653.     ShowMemory(startAt, finishAt - startAt);
  2654.     IF pMoreMem >= finishAt THEN
  2655.         WriteLn('  The first locals declared appear last or are in reg''s.');
  2656.     END;
  2657.  
  2658. {
  2659.  calleeFrame: PREV LINK
  2660.  calleeFrame+4: PREV RA
  2661.  calleeFrame+8: PREV PARAMS
  2662.  MY LOCALS
  2663.  itsFrame: MY LINK
  2664.  itsFrame+4: MY RA
  2665.  itsFrame+8: MY PARAMS (IF A METHOD: callerFrame+8=SELF)
  2666.  NEXT LOCALS
  2667.  callerFrame: NEXT LINK
  2668.  }
  2669.  
  2670. {--------------------------------------------------------------------------------------------------}
  2671. {$S MADebugger}
  2672.  
  2673. PROCEDURE ShowParameters(level: INTEGER;
  2674.                          topFrame: Longint);
  2675.  
  2676.     VAR
  2677.         startAt, finishAt:    Longint;
  2678.         itsFrame, callerFrame: Longint;
  2679.  
  2680.     BEGIN
  2681.     GetLevel(level + 1, topFrame, itsFrame, callerFrame);
  2682.     startAt := itsFrame + 8 + 4 * ord(ord(GetRcvrAtLevel(level, topFrame)) > 0);
  2683.     finishAt := Min(startAt + 80, callerFrame);
  2684.     WriteLn('  The last argument you declared is shown first below.');
  2685.     ShowMemory(startAt, finishAt - startAt);
  2686.     END;
  2687.  
  2688. {--------------------------------------------------------------------------------------------------}
  2689. {$S MADebugger}
  2690.  
  2691. PROCEDURE ShowNames(VAR procName: MAName;
  2692.                     segNum: INTEGER);
  2693.  
  2694.     BEGIN
  2695.     Write(procName);
  2696.     IF segNum > 0 THEN
  2697.         Write(' Seg#: ', segNum: 1);
  2698.     END;
  2699.  
  2700. {--------------------------------------------------------------------------------------------------}
  2701. {$S MADebugger}
  2702.  
  2703. PROCEDURE ShowWhich(which: ZT;
  2704.                     VAR procName: MAName;
  2705.                     segNum: INTEGER);
  2706.  
  2707.     BEGIN
  2708.     CASE which OF
  2709.         tBegin:
  2710.             Write('Begin  ');
  2711.         tEnd:
  2712.             Write('End    ');
  2713.         tExit:
  2714.             Write('Exit   ');
  2715.         tBeginEndPair:
  2716.             Write('BegEnd ');
  2717.         tSysError:
  2718.             Write('SysErr ');
  2719.         tProgBreak:
  2720.             Write('Break  ');
  2721.         tVBL:
  2722.             Write('VBL Break  ');
  2723.     END;
  2724.  
  2725.     ShowNames(procName, segNum);
  2726.     END;
  2727.  
  2728. {--------------------------------------------------------------------------------------------------}
  2729. {$S MADebugger}
  2730.  
  2731. PROCEDURE ShowSymbolWhich(which: ZT;
  2732.                           VAR procName: MAName;
  2733.                           segNum: INTEGER);
  2734.  
  2735.     BEGIN
  2736.     CASE which OF
  2737.         tBegin:
  2738.             Write('>');
  2739.         tEnd:
  2740.             Write('<');
  2741.         tExit:
  2742.             Write('^ Exit: ');
  2743.         tBeginEndPair:
  2744.             Write('');
  2745.         tSysError:
  2746.             Write(': SysErr');
  2747.         tProgBreak:
  2748.             Write(': Break');
  2749.         tVBL:
  2750.             Write(': VBL Break');
  2751.     END;
  2752.     ShowNames(procName, segNum);
  2753.     END;
  2754.  
  2755. {--------------------------------------------------------------------------------------------------}
  2756. {$S MADebugger}
  2757.  
  2758. PROCEDURE ShowRecent;
  2759. { show recent history of pc.  Indents to show nesting level }
  2760.  
  2761.     CONST
  2762.         kIndentMax            = 31;                        { must be a power of 2 minus 1 }
  2763.         kIndentAmount        = 2;                        { number of spaces per nesting level }
  2764.         kDupClassName        = '=';
  2765.         kFailureProc        = 'FAILURE';
  2766.  
  2767.     VAR
  2768.         nextProcName, className, lastClassName: MAName;
  2769.         procName:            MAName;
  2770.         i:                    INTEGER;
  2771.         nexti:                INTEGER;
  2772.         pc:                 Longint;
  2773.         indentLevel, maxIndentLevel: INTEGER;
  2774.         aString:            Str255;
  2775.         aZt:                ZT;
  2776.  
  2777.     BEGIN
  2778.     { get the maximum indenting or outdenting level first }
  2779.     maxIndentLevel := 0;
  2780.     i := BAND(pRecentIndex + 1, kRecent);                { absolute value, modulo kRecent }
  2781.     REPEAT
  2782.         WITH pRecentPC[i] DO
  2783.             IF thePC <> 0 THEN
  2784.                 BEGIN
  2785.                 CASE theZT OF
  2786.                     tBegin:
  2787.                         maxIndentLevel := maxIndentLevel + kIndentAmount;
  2788.                     tEnd, tBeginEndPair:
  2789.                         maxIndentLevel := maxIndentLevel - kIndentAmount;
  2790.                     tExit: ;
  2791.                 END;
  2792.                 END;
  2793.         i := BAND(i + 1, kRecent);                        { absolute value, modulo kRecent }
  2794.     UNTIL i = pRecentIndex;
  2795.  
  2796.     { try to intelligently set a starting indent level }
  2797.     IF maxIndentLevel < 0 THEN                            { some outdenting required }
  2798.         indentLevel := Min(abs(maxIndentLevel), (kIndentMax + 1) DIV 2)
  2799.     ELSE
  2800.         indentLevel := 0;                                { only indents }
  2801.  
  2802.     lastClassName := '';
  2803.     aString := '| | | | | | | | | | | | | | | ';
  2804.     i := BAND(pRecentIndex + 1, kRecent);                { absolute value, modulo kRecent }
  2805.     REPEAT
  2806.         WITH pRecentPC[i] DO
  2807.             IF thePC <> 0 THEN
  2808.                 BEGIN
  2809.                 GetProcName(ord(@thePC), className, procName);
  2810.                 aZt := theZT;
  2811.                 nexti := BAND(i + 1, kRecent);
  2812.                 IF nexti <> pRecentIndex THEN
  2813.                     BEGIN
  2814.                     GetMethodName(ord(@pRecentPC[nexti].thePC), nextProcName);
  2815.                     IF nextProcName = procName THEN
  2816.                         BEGIN
  2817.                         aZt := tBeginEndPair;
  2818.                         i := nexti;
  2819.                         END;
  2820.                     END;
  2821.                 CASE aZt OF
  2822.                     tBegin, tBeginEndPair:
  2823.                         indentLevel := BAND(indentLevel + kIndentAmount, kIndentMax);
  2824.                 END;
  2825.                 aString[0] := CHR(indentLevel);
  2826.                 Write(aString);
  2827.                 CASE aZt OF
  2828.                     tEnd, tBeginEndPair:
  2829.                         indentLevel := BAND(indentLevel - kIndentAmount, kIndentMax);
  2830.                     tExit: ;
  2831.                 END;
  2832.                 IF IsUserBreak THEN
  2833.                     LEAVE;
  2834.                 IF (lastClassName = className) & (length(className) <> 0) THEN
  2835.                     BEGIN
  2836.                     Delete(procName, 1, length(className));
  2837.                     insert(kDupClassName, procName, 1);
  2838.                     END;
  2839.                 lastClassName := className;
  2840.                 ShowSymbolWhich(aZt, procName, - 1);
  2841.                 WriteLn;
  2842.                 IF (aZt = tExit) | ((length(className) = 0) & (procName = kFailureProc)) THEN
  2843.                     WriteLn('------------------------------');
  2844.                 END;
  2845.         i := BAND(i + 1, kRecent);                        { absolute value, modulo kRecent }
  2846.     UNTIL i = pRecentIndex;
  2847.     WriteLn;
  2848.  
  2849.     pMoreMem := - 1;
  2850.     END;
  2851.  
  2852. {--------------------------------------------------------------------------------------------------}
  2853. {$S MADebugger}
  2854.  
  2855. PROCEDURE ShowWhere;
  2856.  
  2857.     BEGIN
  2858.     ShowWhich(which, procName, segNum);
  2859.     IF ord(receiver) > 0 THEN
  2860.         Write('  Self: ', rcvrHandle, ' is ', rcvrClass);
  2861.     WriteLn;
  2862.     END;
  2863.  
  2864. {--------------------------------------------------------------------------------------------------}
  2865. {$S MADebugger}
  2866.  
  2867. PROCEDURE ShowStatus;
  2868.  
  2869.     VAR
  2870.         i:                    INTEGER;
  2871.  
  2872.     BEGIN
  2873.     Write('Trace: ');
  2874.     IF pTraceToggle THEN
  2875.         Write('ON;  ')
  2876.     ELSE
  2877.         Write('OFF; ');
  2878.  
  2879.     {$Ifc qPerform}
  2880.     Write('Performance Monitor: ');
  2881.     IF oldState THEN
  2882.         Write('ON;  ')
  2883.     ELSE
  2884.         Write('OFF; ');
  2885.     {$Endc}
  2886.  
  2887.     IF pBreakCount > 0 THEN
  2888.         BEGIN
  2889.         Write('Break[s] set at: ');
  2890.         FOR i := 1 TO pBreakCount DO
  2891.             BEGIN
  2892.             IF i > 1 THEN
  2893.                 Write(', ');
  2894.             IF pBreakClass[i] <> '' THEN
  2895.                 Write(pBreakClass[i], '.', pBreakProc[i])
  2896.             ELSE
  2897.                 Write(pBreakProc[i]);
  2898.             END;
  2899.         END
  2900.     ELSE
  2901.         Write('No Break set.');
  2902.  
  2903.     WriteLn;
  2904.  
  2905.     Write('Last Broke at: ');
  2906.     ShowWhere;
  2907.     END;
  2908.  
  2909. {--------------------------------------------------------------------------------------------------}
  2910. {$S MADebugger}
  2911.  
  2912. PROCEDURE ShowStack;
  2913.  
  2914.     VAR
  2915.         startLevel:         INTEGER;
  2916.         interrupted:        BOOLEAN;
  2917.     {??? moved strings out to this level to help reduce the stack rqs of recursion.
  2918.     Eventually should fix even better than this ???}
  2919.         className:            MAName;
  2920.         procName:            MAName;
  2921.         rcvrClass:            MAName;
  2922.         rcvrHandle:         HexAddress;
  2923.  
  2924. {--------------------------------------------------------------------------------------------------}
  2925.  
  2926.     PROCEDURE ShowLevel(level: INTEGER;
  2927.                         calleeFrame, ppc: Longint);
  2928.  
  2929.         VAR
  2930.             callerFrame:        Longint;
  2931.             itsFrame:            Longint;
  2932.             receiver:            TObject;
  2933.             segNum:             INTEGER;
  2934.  
  2935.         BEGIN
  2936.         GetFrameInfo(calleeFrame, ppc, callerFrame, itsFrame, receiver, className, procName,
  2937.                      rcvrHandle, rcvrClass, segNum);
  2938.  
  2939.         IF calleeFrame <> itsFrame THEN
  2940.             BEGIN
  2941.             nextLevel := level + 1;
  2942.             nextFrame := itsFrame;
  2943.             pNextPC := itsFrame + 4;
  2944.             IF nextLevel < startLevel + 10 THEN
  2945.                 ShowLevel(nextLevel, nextFrame, pNextPC)
  2946.             ELSE
  2947.                 pMoreMem := 0;                            {Signal that "More" command is available}
  2948.             END;
  2949.  
  2950.         IF NOT interrupted THEN
  2951.             BEGIN
  2952.             Write(' ', level: 3, ' ');
  2953.             WritePtr(calleeFrame);
  2954.             Write(': ');
  2955.  
  2956.             { retrieve names for this frame again }
  2957.             GetFrameInfo(calleeFrame, ppc, callerFrame, itsFrame, receiver, className, procName,
  2958.                          rcvrHandle, rcvrClass, segNum);
  2959.  
  2960.             ShowNames(procName, segNum);
  2961.             IF ord(receiver) > 0 THEN
  2962.                 Write('  Self: ', rcvrHandle, ' is ', rcvrClass);
  2963.             WriteLn;
  2964.             interrupted := IsUserBreak;
  2965.             END;
  2966.         END;
  2967.  
  2968.     BEGIN
  2969.     pMoreMem := - 1;
  2970.     interrupted := FALSE;
  2971.     startLevel := nextLevel;
  2972.  
  2973.     ShowLevel(startLevel, nextFrame, pNextPC);
  2974.  
  2975.     IF pMoreMem = 0 THEN
  2976.         WriteLn('More… [M]: ');
  2977.     END;
  2978.  
  2979. {--------------------------------------------------------------------------------------------------}
  2980. {$S MAUtilitiesRes}                                     { Shouldn't be unloaded }
  2981. {$Push} {$Z+}
  2982.  
  2983. PROCEDURE EachFrameDo(calleeFrame, ppc: Longint;
  2984.                       PROCEDURE DoToFrame(calleeFrame: Longint;
  2985.                                           ppc: Longint;
  2986.                                           callerFrame: Longint;
  2987.                                           itsFrame: Longint));
  2988.  
  2989.     PROCEDURE DoLevel(calleeFrame, ppc: Longint);
  2990.  
  2991.         VAR
  2992.             callerFrame:        Longint;
  2993.             itsFrame:            Longint;
  2994.             nextFrame:            Longint;
  2995.             pNextPC:            Longint;
  2996.  
  2997.         BEGIN
  2998.         GetLevel(1, calleeFrame, itsFrame, callerFrame);
  2999.         DoToFrame(calleeFrame, ppc, callerFrame, itsFrame);
  3000.         IF calleeFrame <> itsFrame THEN
  3001.             BEGIN
  3002.             nextFrame := itsFrame;
  3003.             pNextPC := itsFrame + 4;
  3004.             DoLevel(nextFrame, pNextPC)
  3005.             END;
  3006.         END;
  3007.  
  3008.     BEGIN
  3009.     DoLevel(calleeFrame, ppc);
  3010.     END;
  3011. {$Pop}
  3012.  
  3013. {--------------------------------------------------------------------------------------------------}
  3014. {$S MADebugger}
  3015.  
  3016. PROCEDURE ShowTempSpace(VAR lockedSpace, totalSpace: Longint);
  3017.  
  3018.     VAR
  3019.         seg:                Handle;
  3020.  
  3021.     BEGIN
  3022.     lockedSpace := TotalTempSize(true, seg);
  3023.     totalSpace := TotalTempSize(FALSE, seg);
  3024.  
  3025.     WriteLn('  Current temp space: locked = ', lockedSpace: 1, ', unlocked = ', totalSpace -
  3026.             lockedSpace: 1, ', total = ', totalSpace: 1);
  3027.  
  3028.     END;
  3029.  
  3030. {--------------------------------------------------------------------------------------------------}
  3031. {$S MADebugger}
  3032.  
  3033. PROCEDURE ShowHeapInfo;
  3034.  
  3035.     VAR
  3036.         codeRes:            Longint;
  3037.         codeShort:            Longint;
  3038.         lockedSpace:        Longint;
  3039.         lowSpaceRes:        Longint;
  3040.         okCode:             BOOLEAN;
  3041.         okLowSpace:         BOOLEAN;
  3042.         oldPerm:            BOOLEAN;
  3043.         oldRsrcUse:         Longint;
  3044.         purgeSpace:         Longint;
  3045.         totalSpace:         Longint;
  3046.  
  3047.     BEGIN
  3048.     oldRsrcUse := gMaxLockedRsrc;
  3049.  
  3050.     {== S T A C K ==}
  3051.     WriteLn('STACK');
  3052.     WriteLn('  Current total stack = ', pStackSpace: 1, '           Maximum stack used = ',
  3053.             gMaxStackDepth: 1);
  3054.     WriteLn('  Current procedure stack = ', pProcStack: 1, '           Available stack = ',
  3055.             ord(GetCurStackBase) - ord(GetApplLimit): 1);
  3056.  
  3057.     IF pBreakStack < $7FFFFFFF THEN
  3058.         WriteLn('Break at total stack space = ', pBreakStack: 1);
  3059.     IF pBrProcStack < $7FFFFFFF THEN
  3060.         WriteLn('Break at procedure stack space = ', pBrProcStack: 1);
  3061.  
  3062.     {== R E S E R V E S ==}
  3063.     WriteLn('RESERVES');
  3064.     DoChangeReserve(FALSE, codeRes, codeShort, lowSpaceRes, okCode, okLowSpace);
  3065.  
  3066.     Write('  code = ', codeRes: 1);
  3067.     IF okCode THEN
  3068.         Write(' (OK)')
  3069.     ELSE
  3070.         Write(' (low: ', codeShort: 1, ')');
  3071.  
  3072.     Write('     low space = ', lowSpaceRes: 1);
  3073.     IF okLowSpace THEN
  3074.         Write(' (OK)')
  3075.     ELSE
  3076.         Write(' (gone)');
  3077.  
  3078.     Write('  allocation flag: ');
  3079.     IF pPermFlag THEN
  3080.         WriteLn('permanent')
  3081.     ELSE
  3082.         WriteLn('temporary');
  3083.  
  3084.     {== T E M P  S P A C E ==}
  3085.     WriteLn('TEMP SPACE');
  3086.     ShowTempSpace(lockedSpace, totalSpace);
  3087.  
  3088.     purgeSpace := totalSpace - codeRes;
  3089.     IF purgeSpace > (totalSpace - lockedSpace) THEN
  3090.         purgeSpace := totalSpace - lockedSpace;
  3091.  
  3092.     IF purgeSpace >= 0 THEN
  3093.         WriteLn('  Purgeable temp space = ', purgeSpace: 1)
  3094.     ELSE
  3095.         WriteLn('  Needed reserve handle size = ', - purgeSpace: 1);
  3096.  
  3097.     {== O T H E R ==}
  3098.     WriteLn('OTHER');
  3099.     CheckRsrcUsage;
  3100.  
  3101.     Write('  Max resource usage = ', gMaxLockedRsrc: 1);
  3102.     IF oldRsrcUse <> gMaxLockedRsrc THEN
  3103.         WriteLn(' (new)')
  3104.     ELSE
  3105.         WriteLn;
  3106.  
  3107.     gMaxLockedRsrc := oldRsrcUse;                        { so we get the '(new)' indications again }
  3108.  
  3109.     oldPerm := PermAllocation(true);
  3110.     totalSpace := FreeMem;
  3111.     oldPerm := PermAllocation(oldPerm);
  3112.  
  3113.     WriteLn('  (permanent) FreeMem = ', totalSpace: 1, '            Free master pointers = ',
  3114.             GetFreeMastersCount: 1);
  3115.     END;
  3116.  
  3117. {--------------------------------------------------------------------------------------------------}
  3118. {$S MADebugger}
  3119.  
  3120. PROCEDURE HeapCmd;
  3121.  
  3122.     VAR
  3123.         ch:                 CHAR;
  3124.         decNum:             Longint;
  3125.         done:                BOOLEAN;
  3126.         hexNum:             Longint;
  3127.         x:                    Longint;
  3128.         y:                    Longint;
  3129.  
  3130.         id:                 INTEGER;
  3131.         name:                Str255;
  3132.         nSeg:                INTEGER;
  3133.         seg:                Handle;
  3134.         t:                    ResType;
  3135.  
  3136.         codeRes:            Longint;
  3137.         codeShort:            Longint;
  3138.         lowSpaceRes:        Longint;
  3139.         okCode:             BOOLEAN;
  3140.         okLowSpace:         BOOLEAN;
  3141.         oldPerm:            BOOLEAN;
  3142.  
  3143.     PROCEDURE helpProc;
  3144.  
  3145.         BEGIN
  3146.         WriteLn;
  3147.         WriteLn('+ -- set breakpoint on procedure stack usage');
  3148.         WriteLn('B -- set breakpoint on total stack usage');
  3149.         WriteLn('D -- reset maximum stack depth');
  3150.         WriteLn('I -- show heap/stack info');
  3151.         WriteLn('M -- show heap/stack info AND MaxMem');
  3152.         WriteLn('R -- show/set heap reserve');
  3153.         WriteLn('S -- list LOADED segments');
  3154.         WriteLn('ß (option-S) -- list ALL segments');
  3155.         WriteLn;
  3156.         END;
  3157.  
  3158.     PROCEDURE ShowSegments(allSegments: BOOLEAN);
  3159.     { Show segment information.  if allSegments is true then also show unloaded & purged }
  3160.  
  3161.         VAR
  3162.             i:                    INTEGER;
  3163.  
  3164.         BEGIN
  3165.         codeRes := 0;                                    { counts size of code segments }
  3166.  
  3167.         nSeg := GetHandleSize(Handle(gCodeSegs)) DIV sizeof(Handle);
  3168.  
  3169.         WriteLn('Total # segments = ', nSeg: 1);
  3170.         IF allSegments THEN
  3171.             WriteLn(
  3172.         '• = resident, L = loaded, U = unloaded (and relocatable), '' '' = purged (or never loaded)'
  3173.                     )
  3174.         ELSE
  3175.             WriteLn('• = resident, L = loaded');
  3176.  
  3177.         FOR i := 1 TO nSeg DO
  3178.             BEGIN
  3179.             seg := gCodeSegs^^[i];
  3180.             IF allSegments | (NOT IsHandlePurged(seg) & isHandleLocked(seg)) THEN
  3181.                 BEGIN
  3182.                 GetResInfo(seg, id, t, name);
  3183.  
  3184.                 WritePtr(seg);
  3185.  
  3186.                 Write('  Seg#:', id: 3, ' ');
  3187.  
  3188.                 IF gIsResidentSeg^^[i] THEN
  3189.                     Write('• ')
  3190.                 ELSE IF IsHandlePurged(seg) THEN
  3191.                     Write('  ')
  3192.                 ELSE IF gIsLoadedSeg^^[i] THEN
  3193.                     Write('L ')
  3194.                 ELSE
  3195.                     Write('U ');
  3196.  
  3197.                 Write(name, ' ': 25 - length(name), ' ');
  3198.  
  3199.                 WriteLn(pSegSize^^[i]: 6, ' bytes');
  3200.  
  3201.                 codeRes := codeRes + pSegSize^^[i] + 8;
  3202.                 END;
  3203.             END;
  3204.  
  3205.         WriteLn;
  3206.         WriteLn('Total loaded code = ', codeRes: 1);
  3207.         ShowTempSpace(x, y);
  3208.         END;
  3209.  
  3210.     BEGIN
  3211.     done := FALSE;
  3212.     REPEAT
  3213.         ch := GetPromptedChar(AtStr('Heap/Stack Cmd'), AtStr('+BDIMRSß'), helpProc);
  3214.  
  3215.         CASE ch OF
  3216.             '+':
  3217.                 BEGIN
  3218.                 IF GetPromptedNumber(AtStr('Break at what procedure stack usage?: '), decNum,
  3219.                                      hexNum) THEN
  3220.  
  3221.                     IF decNum = 0 THEN
  3222.                         pBrProcStack := $7FFFFFFF
  3223.                     ELSE IF decNum > 0 THEN
  3224.                         pBrProcStack := decNum;
  3225.  
  3226.                 ShowHeapInfo;
  3227.  
  3228.                 done := true;
  3229.                 END;
  3230.  
  3231.             'B':
  3232.                 BEGIN
  3233.                 IF GetPromptedNumber(AtStr('Break at what total stack usage?: '), decNum,
  3234.                    hexNum) THEN
  3235.                     IF decNum = 0 THEN
  3236.                         pBreakStack := $7FFFFFFF
  3237.                     ELSE IF decNum > 0 THEN
  3238.                         pBreakStack := decNum;
  3239.  
  3240.                 ShowHeapInfo;
  3241.  
  3242.                 done := true;
  3243.                 END;
  3244.  
  3245.             'D':
  3246.                 BEGIN
  3247.                 gMaxStackDepth := - 1;
  3248.  
  3249.                 ShowHeapInfo;
  3250.  
  3251.                 done := true;
  3252.                 END;
  3253.  
  3254.             'I':
  3255.                 BEGIN
  3256.                 ShowHeapInfo;
  3257.                 done := true;
  3258.                 END;
  3259.  
  3260.             'M':
  3261.                 BEGIN
  3262.                 oldPerm := PermAllocation(true);
  3263.                 x := MaxMem(decNum);
  3264.                 oldPerm := PermAllocation(oldPerm);
  3265.  
  3266.                 ShowHeapInfo;
  3267.  
  3268.                 WriteLn('(permanent) MaxMem = ', x: 1);
  3269.  
  3270.                 done := true;
  3271.                 END;
  3272.  
  3273.             'R':
  3274.                 BEGIN
  3275.                 DoChangeReserve(true, codeRes, codeShort, lowSpaceRes, okCode, okLowSpace);
  3276.                 ShowHeapInfo;
  3277.                 done := true;
  3278.                 END;
  3279.  
  3280.             'S':
  3281.                 BEGIN
  3282.                 ShowSegments(FALSE);
  3283.  
  3284.                 done := true;
  3285.                 END;
  3286.  
  3287.             'ß':
  3288.                 BEGIN
  3289.                 ShowSegments(true);
  3290.  
  3291.                 done := true;
  3292.                 END;
  3293.  
  3294.             OTHERWISE
  3295.                 done := true;
  3296.         END;
  3297.     UNTIL done;
  3298.     END;
  3299.  
  3300. {--------------------------------------------------------------------------------------------------}
  3301. {$S MADebugger}
  3302.  
  3303. PROCEDURE PositionDebugWindow(where: CHAR);
  3304.  
  3305.     VAR
  3306.         theEvent:            EventRecord;
  3307.  
  3308.     BEGIN
  3309.     CASE where OF
  3310.         'B':
  3311.             BEGIN
  3312.             SendBehind(pDebugWindow.fWMgrWindow, NIL);
  3313.             WHILE GetNextEvent(activMask, theEvent) DO; { suck up the activate/deactivate }
  3314.             HiliteWindow(pDebugWindow.fWMgrWindow, true);
  3315.             END;
  3316.         'F':
  3317.             BringToFront(pDebugWindow.fWMgrWindow);
  3318.     END;
  3319.     END;
  3320.  
  3321. {--------------------------------------------------------------------------------------------------}
  3322. {$S MADebugger}
  3323.  
  3324. PROCEDURE WindCmd;
  3325.  
  3326.     CONST
  3327.         kVMargin            = 4;
  3328.         kHMargin            = 4;
  3329.  
  3330.     VAR
  3331.         done:                BOOLEAN;
  3332.         ch:                 CHAR;
  3333.         aTextStyle:         TextStyle;
  3334.  
  3335.     PROCEDURE helpProc;
  3336.  
  3337.         BEGIN
  3338.         WriteLn;
  3339.         WriteLn('B -- send debug window to the back');
  3340.         WriteLn('F -- bring debug window to front');
  3341.         WriteLn('ƒ -- specify a font');
  3342.         WriteLn('S -- specify a font size');
  3343.         WriteLn;
  3344.         END;
  3345.  
  3346.     PROCEDURE InstallTheStyle(aTextStyle: TextStyle);
  3347.  
  3348.         VAR
  3349.             zoomedOutSize:        Point;
  3350.  
  3351.         BEGIN
  3352.         {$Push} {$H-}
  3353.         zoomedOutSize := VPtToPt(pDebugView.fSize);
  3354.         {$Pop}
  3355.         WITH zoomedOutSize DO
  3356.             BEGIN
  3357.             v := (2 * kVMargin) + (pDebugView.fFontHeight * (pDebugView.fRows));
  3358.             v := max(kSBarSize * 4, v + kSBarSize);
  3359.             h := max(kSBarSize * 4, h + kSBarSize);
  3360.             END;
  3361.  
  3362.         pDebugWindow.SetResizeLimits(gStdWSizeRect.topLeft, zoomedOutSize);
  3363.         pDebugView.InstallTextStyle(aTextStyle);
  3364.         pDebugView.ForceRedraw;
  3365.         END;
  3366.  
  3367.     PROCEDURE FontHelpProc;
  3368.  
  3369.         VAR
  3370.             theCount, i:        INTEGER;
  3371.             h:                    Handle;
  3372.             oldResLoad:         BOOLEAN;
  3373.             theID:                INTEGER;
  3374.             theType:            ResType;
  3375.             name:                Str255;
  3376.  
  3377.         BEGIN
  3378.         WriteLn;
  3379.         theCount := CountResources('FOND');
  3380.         FOR i := 1 TO theCount DO
  3381.             BEGIN
  3382.             oldResLoad := GetResLoad;
  3383.             SetResLoad(FALSE);
  3384.             h := GetIndResource('FOND', i);
  3385.             IF h <> NIL THEN
  3386.                 BEGIN
  3387.                 GetResInfo(h, theID, theType, name);
  3388.                 SetResLoad(oldResLoad);
  3389.                 WriteLn(name);
  3390.                 END
  3391.             ELSE
  3392.                 SetResLoad(oldResLoad);
  3393.             END;
  3394.         END;
  3395.  
  3396.     BEGIN
  3397.     done := FALSE;
  3398.     REPEAT
  3399.         ch := GetPromptedChar(AtStr('Window Cmd'), AtStr('BFƒS'), helpProc);
  3400.  
  3401.         CASE ch OF
  3402.             'B', 'F':
  3403.                 BEGIN
  3404.                 PositionDebugWindow(ch);
  3405.                 done := true;
  3406.                 END;
  3407.             'ƒ':                                        {??? from a menu some other time }
  3408.                 BEGIN
  3409.                 aTextStyle := pDebugView.fTextStyle;
  3410.                 aTextStyle.tsFont := GetFontNum(GetPromptedString(AtStr('Enter font name?: '),
  3411.                                                                   FontHelpProc));
  3412.                 InstallTheStyle(aTextStyle);
  3413.                 done := true;
  3414.                 END;
  3415.             'S':                                        {??? from a menu some other time }
  3416.                 BEGIN
  3417.                 IF GetPromptedNumber(AtStr('Enter font size?: '), asDecimal, asHex) THEN
  3418.                     BEGIN
  3419.                     aTextStyle := pDebugView.fTextStyle;
  3420.                     aTextStyle.tsSize := asDecimal;
  3421.                     InstallTheStyle(aTextStyle);
  3422.                     END;
  3423.                 done := true;
  3424.                 END;
  3425.             OTHERWISE
  3426.                 done := true;
  3427.         END;
  3428.     UNTIL done;
  3429.     END;
  3430.  
  3431. {--------------------------------------------------------------------------------------------------}
  3432. {$S MADebugger}
  3433.  
  3434. PROCEDURE SetBreakCmd;
  3435.  
  3436.     VAR
  3437.         done:                BOOLEAN;
  3438.         ch:                 CHAR;
  3439.         aClassName, aProcName: MAName;
  3440.  
  3441.     BEGIN
  3442.     IF pBreakCount < 10 THEN
  3443.         BEGIN
  3444.         IF GetPromptedNames(AtStr('Break at [Typename.ProcName or ProcName]?: '), aClassName,
  3445.                             aProcName) THEN
  3446.             BEGIN
  3447.             pBreakCount := pBreakCount + 1;
  3448.             pBreakClass[pBreakCount] := aClassName;
  3449.             pBreakProc[pBreakCount] := aProcName;
  3450.             END
  3451.         END
  3452.     ELSE
  3453.         WriteLn('Already have maximum breakpoints set!');
  3454.     ShowStatus;
  3455.     END;
  3456.  
  3457. {--------------------------------------------------------------------------------------------------}
  3458. {$S MADebugger}
  3459.  
  3460. PROCEDURE ClrBreakCmd;
  3461.  
  3462.     VAR
  3463.         aString:            Str255;
  3464.         whichBreak:         Longint;
  3465.  
  3466.     PROCEDURE ClrBreakHelp;
  3467.  
  3468.         VAR
  3469.             i:                    INTEGER;
  3470.  
  3471.         BEGIN
  3472.         WriteLn;
  3473.         WriteLn('A - All breakpoints');
  3474.         FOR i := 1 TO pBreakCount DO
  3475.             BEGIN
  3476.             Write(i: 1, ' - ');
  3477.             IF pBreakClass[i] <> '' THEN
  3478.                 WriteLn(pBreakClass[i], '.', pBreakProc[i])
  3479.             ELSE
  3480.                 WriteLn(pBreakProc[i]);
  3481.             END;
  3482.         END;
  3483.  
  3484.     BEGIN
  3485.     CASE pBreakCount OF
  3486.         0:
  3487.             WriteLn('No breakpoints are set!.');
  3488.         1:
  3489.             BEGIN
  3490.             pBreakCount := 0;
  3491.             WriteLn('Cleared the breakpoint.');
  3492.             END;
  3493.         OTHERWISE
  3494.             BEGIN
  3495.             aString := concat(ConcatNumber('Which breakpoint[1-', pBreakCount), ',A]?:');
  3496.             aString := GetPromptedString(@aString, ClrBreakHelp);
  3497.             UprStr255(aString);
  3498.             IF aString = 'A' THEN
  3499.                 BEGIN
  3500.                 pBreakCount := 0;
  3501.                 WriteLn('Cleared all the breakpoints.');
  3502.                 END
  3503.             ELSE IF aString <> '' THEN
  3504.                 BEGIN
  3505.                 StringToNum(aString, whichBreak);
  3506.                 IF (whichBreak > 0) & (whichBreak <= pBreakCount) THEN
  3507.                     BEGIN
  3508.                     WHILE whichBreak < pBreakCount DO
  3509.                         BEGIN
  3510.                         pBreakClass[whichBreak] := pBreakClass[whichBreak + 1];
  3511.                         pBreakProc[whichBreak] := pBreakProc[whichBreak + 1];
  3512.                         whichBreak := whichBreak + 1;
  3513.                         END;
  3514.                     pBreakCount := pBreakCount - 1;
  3515.                     WriteLn('Cleared the breakpoint.');
  3516.                     END;
  3517.                 END;
  3518.             END;
  3519.     END;
  3520.     ShowStatus;
  3521.     END;
  3522.  
  3523. {--------------------------------------------------------------------------------------------------}
  3524. {$Ifc qPerform}
  3525. {$S MADebugger}
  3526.  
  3527. PROCEDURE PerfCmd;
  3528.  
  3529.     VAR
  3530.         done:                BOOLEAN;
  3531.         ch:                 CHAR;
  3532.         aBool:                BOOLEAN;
  3533.         perfErr:            INTEGER;
  3534.         s:                    Str255;
  3535.         ms:                 INTEGER;
  3536.         apName:             Str255;
  3537.         apRefnum:            INTEGER;
  3538.         apParam:            Handle;
  3539.  
  3540.     PROCEDURE helpProc;
  3541.  
  3542.         BEGIN
  3543.         WriteLn;
  3544.         WriteLn('D -- Dump to output file');
  3545.         WriteLn('E -- End the tools and free their storage');
  3546.         WriteLn('I -- Init performance tools');
  3547.         WriteLn('T -- Toggle tools on and off');
  3548.         WriteLn;
  3549.         END;
  3550.  
  3551.     PROCEDURE appCodeTypeHelpProc;
  3552.  
  3553.         BEGIN
  3554.         WriteLn;
  3555.         WriteLn('Please specify the resource type to measure');
  3556.         WriteLn;
  3557.         END;
  3558.  
  3559.     PROCEDURE romNameHelpProc;
  3560.  
  3561.         BEGIN
  3562.         WriteLn;
  3563.         WriteLn('Please specify the ROM name');
  3564.         WriteLn;
  3565.         END;
  3566.  
  3567.     PROCEDURE reportFileHelpProc;
  3568.  
  3569.         BEGIN
  3570.         WriteLn;
  3571.         WriteLn('Please specify a file name for the report');
  3572.         WriteLn;
  3573.         END;
  3574.  
  3575.     BEGIN
  3576.     done := FALSE;
  3577.     REPEAT
  3578.         ch := GetPromptedChar(AtStr('Performance Cmd'), AtStr('DEIT'), helpProc);
  3579.  
  3580.         CASE ch OF
  3581.             'D':
  3582.                 BEGIN
  3583.                 IF pTP2PerfGlobals <> NIL THEN
  3584.                     BEGIN
  3585.                     WriteLn('Dump performance tools data.  Press Return to take the default…');
  3586.                     GetAppParms(apName, apRefnum, apParam);
  3587.                     s := concat(apName, '.perf');
  3588.                     perfErr := PerfDump(pTP2PerfGlobals,
  3589.                                         GetPromptedStringWithDefault(AtStr('  reportFile'), @s,
  3590.                                         reportFileHelpProc), GetPromptedNumberWithDefault(AtStr(
  3591.                                         '  doHistogram (TRUE=1/FALSE=0)'), 0) = 1,
  3592.                                         GetPromptedNumberWithDefault(AtStr('  rptFileColumns'),
  3593.                                80));
  3594.                     IF perfErr <> noErr THEN
  3595.                         WriteLn('Error: ', perfErr, ' while dumping');
  3596.                     END
  3597.                 ELSE
  3598.                     WriteLn('Not initialized!');
  3599.                 done := true;
  3600.                 END;
  3601.             'E':
  3602.                 BEGIN
  3603.                 IF pTP2PerfGlobals <> NIL THEN
  3604.                     BEGIN
  3605.                     TermPerf(pTP2PerfGlobals);
  3606.                     pTP2PerfGlobals := NIL;
  3607.                     END
  3608.                 ELSE
  3609.                     WriteLn('Not initialized!');
  3610.                 done := true;
  3611.                 END;
  3612.             'I':
  3613.                 BEGIN
  3614.                 IF pTP2PerfGlobals = NIL THEN
  3615.                     BEGIN
  3616.                     WriteLn('Init performance tools.  Press Return to take the default…');
  3617.                     { set the default }
  3618.                     CASE gConfiguration.machineType OF
  3619.                         envMac, envXL, env512KE, envMacPlus, envSE:
  3620.                             ms := 10;
  3621.                         OTHERWISE
  3622.                             ms := 4;
  3623.                     END;
  3624.                     aBool := InitPerf(pTP2PerfGlobals,
  3625.                                       GetPromptedNumberWithDefault(AtStr('  timerCount'), ms),
  3626.                                       GetPromptedNumberWithDefault(AtStr('  codeAndROMBucketSize'),
  3627.                                                                    8),
  3628.                                       GetPromptedNumberWithDefault(AtStr('  doROM (TRUE=1/FALSE=0)'
  3629.                                                                           ), 0) = 1,
  3630.                                       GetPromptedNumberWithDefault(AtStr(
  3631.                                                                       '  doAppCode (TRUE=1/FALSE=0)'
  3632.                                                                          ), 1) = 1,
  3633.                                       GetPromptedStringWithDefault(AtStr('  appCodeType'),
  3634.                                                                    AtStr('CODE'),
  3635.                                                                    appCodeTypeHelpProc),
  3636.                                       GetPromptedNumberWithDefault(AtStr('  romID'), 0),
  3637.                                       GetPromptedStringWithDefault(AtStr('  romName'), AtStr(''),
  3638.                                                                    romNameHelpProc),
  3639.                                       GetPromptedNumberWithDefault(AtStr('  doRAM (TRUE=1/FALSE=0)')
  3640.                                                                    , 0) = 1,
  3641.                                       GetPromptedNumberWithDefault(AtStr('  ramLow'), 0),
  3642.                                       GetPromptedNumberWithDefault(AtStr('  ramHigh'), 0),
  3643.                                       GetPromptedNumberWithDefault(AtStr('  ramBucketSize'), 8));
  3644.                     IF NOT aBool THEN
  3645.                         WriteLn('Performance tools initialization FAILED.');
  3646.                     END
  3647.                 ELSE
  3648.                     WriteLn('Already initialized!');
  3649.  
  3650.                 done := true;
  3651.                 END;
  3652.             'T':
  3653.                 BEGIN
  3654.                 IF pTP2PerfGlobals <> NIL THEN
  3655.                     BEGIN
  3656.                     oldState := NOT oldState;
  3657.                     ShowStatus;
  3658.                     END
  3659.                 ELSE
  3660.                     WriteLn('Not initialized!');
  3661.                 done := true;
  3662.                 END;
  3663.             OTHERWISE
  3664.                 done := true;
  3665.         END;
  3666.     UNTIL done;
  3667.     END;
  3668. {$Endc}
  3669. {--------------------------------------------------------------------------------------------------}
  3670. {$S MADebugger}
  3671.  
  3672. PROCEDURE ToggleCmd;
  3673.  
  3674.     VAR
  3675.         done:                BOOLEAN;
  3676.         ch:                 CHAR;
  3677.         i:                    INTEGER;
  3678.         theFlags:            Str255;
  3679.         newState:            BOOLEAN;
  3680.  
  3681.     PROCEDURE FlagInfo(desc: StringHandle;
  3682.                        addr: BooleanPtr);
  3683.  
  3684.         BEGIN
  3685.         HLock(Handle(desc));
  3686.         {$Push} {$H-}
  3687.         Write(desc^^, ': ');
  3688.         {$Pop}
  3689.         HUnLock(Handle(desc));
  3690.         IF addr^ THEN
  3691.             WriteLn('TRUE')
  3692.         ELSE
  3693.             WriteLn('FALSE');
  3694.         END;
  3695.  
  3696.     PROCEDURE helpProc;
  3697.  
  3698.         VAR
  3699.             i:                    INTEGER;
  3700.  
  3701.         BEGIN
  3702.         WriteLn;
  3703.         FOR i := 1 TO pFlagsInUse DO
  3704.             WITH pFlagTable[i] DO
  3705.                 BEGIN
  3706.                 Write(ch, ' -- ');
  3707.                 FlagInfo(desc, addr);
  3708.                 END;
  3709.         WriteLn;
  3710.         END;
  3711.  
  3712.     BEGIN
  3713.     done := FALSE;
  3714.     REPEAT
  3715.         theFlags := '';
  3716.         FOR i := 1 TO pFlagsInUse DO
  3717.             BEGIN
  3718.             IF pFlagTable[i].addr^ THEN
  3719.                 theFlags[length(theFlags) + 1] := UprChar(pFlagTable[i].ch)
  3720.             ELSE
  3721.                 theFlags[length(theFlags) + 1] := LowerChar(pFlagTable[i].ch);
  3722.             theFlags[0] := CHR(length(theFlags) + 1);
  3723.             END;
  3724.  
  3725.         ch := GetPromptedChar(AtStr('Toggle Flag'), @theFlags, helpProc);
  3726.         CASE ch OF
  3727.             chReturn:
  3728.                 done := true;
  3729.             OTHERWISE
  3730.                 BEGIN
  3731.                 i := 1;
  3732.                 WHILE NOT done & (i <= pFlagsInUse) DO
  3733.                     BEGIN
  3734.                     IF pFlagTable[i].ch = ch THEN
  3735.                         BEGIN
  3736.                         newState := NOT pFlagTable[i].addr^;
  3737.                         IF pFlagTable[i].actionProc <> NIL THEN
  3738.                             IF CallFlagActionProc(newState, pFlagTable[i].actionProc) THEN; {
  3739.                             discard result }
  3740.                         pFlagTable[i].addr^ := newState;
  3741.                         FlagInfo(pFlagTable[i].desc, pFlagTable[i].addr);
  3742.                         done := true;
  3743.                         END;
  3744.                     i := i + 1;
  3745.                     END;
  3746.                 END;
  3747.         END;
  3748.     UNTIL done;
  3749.     END;
  3750.  
  3751. {--------------------------------------------------------------------------------------------------}
  3752. {$S MADebugger}
  3753.  
  3754. PROCEDURE MainHelpProc;
  3755.  
  3756.     BEGIN
  3757.     WriteLn;
  3758.     Write('A5: ');
  3759.     WritePtr(GetA5);
  3760.     Write('; thePort: ');
  3761.     WritePtr(pSavedState.pFocusRec.Port);
  3762.     WriteLn;
  3763.     ShowStatus;
  3764.     WriteLn('?/Help -- Display Help');
  3765.     WriteLn('/ -- Show Status');
  3766.     WriteLn('B -- Set a breakpoint');
  3767.     WriteLn('C -- Clear a breakpoint');
  3768.     WriteLn('D -- Display Memory');
  3769.     {$IFC IncludeDisassembler}
  3770.     WriteLn('∂ (option-d) -- Disassemble Memory');
  3771.     {$EndC}
  3772.     WriteLn('E -- Enter Macsbug (or other low-level debugger)');
  3773.     WriteLn('F -- Fields');
  3774.     WriteLn('G -- Go');
  3775.     WriteLn('H -- Heap & Stack…');
  3776.     WriteLn('I -- Inspect');
  3777.     WriteLn('L -- Locals');
  3778.     WriteLn('M -- More');
  3779.     {$IFC IncludeDisassembler}
  3780.     WriteLn('µ (option-m) -- Disassemble More');
  3781.     {$EndC}
  3782.     WriteLn('O -- Output Redirection');
  3783.     WriteLn('P -- Parameters');
  3784.     {$Ifc qPerform}
  3785.     WriteLn('π (option-p) -- Performance Monitor…');
  3786.     {$Endc}
  3787.     WriteLn('Q -- Quit');
  3788.     WriteLn('R -- Recent PC history');
  3789.     WriteLn('S -- Stack Crawl');
  3790.     WriteLn('ß (option-s) -- Signal Failure(0, 0)');
  3791.     WriteLn('T -- Trace toggle');
  3792.     WriteLn('W -- Window…');
  3793.     WriteLn('X -- Toggle Flag…');
  3794.     WriteLn('Space -- Single step OVER deeper levels');
  3795.     WriteLn('Option-Space -- Single step INTO deeper levels');
  3796.     WriteLn('Cmd-BS/Cmd-CR, Arrows, Page keys -- Scroll');
  3797.     WriteLn('Cmd-` -- Break at normal entry');
  3798.     WriteLn('Cmd-Option-Shift -- Break at next procedure boundary');
  3799.     WriteLn('Cmd-Option-Control-Shift -- Break at next VBL (Danger Will Robinson!)');
  3800.     WriteLn;
  3801.     END;
  3802.  
  3803. {--------------------------------------------------------------------------------------------------}
  3804. {$S MADebugger}
  3805.  
  3806. PROCEDURE DoWaiting;
  3807.  
  3808.     CONST
  3809.         chOptionSpace        = ' ';
  3810.  
  3811.     VAR
  3812.         error, message:     INTEGER;
  3813.         gotSymbol:            BOOLEAN;
  3814.         savedScript:        INTEGER;
  3815.  
  3816.     PROCEDURE RedirectHelpProc;
  3817.  
  3818.         BEGIN
  3819.         WriteLn;
  3820.         WriteLn('Please supply a valid filename.  ''>>filename'' to append to the file');
  3821.         WriteLn;
  3822.         END;
  3823.  
  3824.     BEGIN
  3825.     pMoreMem := - 1;
  3826.     IF NOT gInBackground THEN
  3827.         HiliteMenu(mDebug)
  3828.     ELSE IF FALSE THEN
  3829.         InstallAnNMRequest;
  3830.  
  3831.     WHILE waiting DO
  3832.         BEGIN
  3833.         IF pAtBreak THEN
  3834.             BEGIN
  3835.             FlushEvents(keyDownMask + autoKeyMask, 0);
  3836.             pAtBreak := FALSE;
  3837.             END;
  3838.  
  3839.         {$Ifc qPerform}
  3840.         ch := GetPromptedChar(AtStr('Command'), AtStr('  BCDEFGHILMOPπQRSßTWX/'), MainHelpProc);
  3841.         {$ElseC}
  3842.         ch := GetPromptedChar(AtStr('Command'), AtStr('  BCDEFGHILMOPQRSßTWX/'), MainHelpProc);
  3843.         {$Endc}
  3844.         CASE ch OF
  3845.             '/':
  3846.                 BEGIN
  3847.                 WriteLn;
  3848.                 Write('A5: ');
  3849.                 WritePtr(GetA5);
  3850.                 Write('; thePort: ');
  3851.                 WritePtr(pSavedState.pFocusRec.Port);
  3852.                 WriteLn;
  3853.                 ShowStatus;
  3854.                 END;
  3855.  
  3856.             'B':
  3857.                 SetBreakCmd;
  3858.  
  3859.             'C':
  3860.                 ClrBreakCmd;
  3861.  
  3862.             'D':
  3863.                 BEGIN
  3864.                 IF GetPromptedNumber(AtStr('Display memory starting where?: '), asDecimal,
  3865.                    asHex) THEN
  3866.                     IF asHex <> - 1 THEN
  3867.                         ShowMemory(asHex, 16);
  3868.                 END;
  3869.  
  3870.             {$IFC IncludeDisassembler}
  3871.             '∂':
  3872.                 BEGIN
  3873.                 IF GetPromptedNumber(AtStr('Disassemble memory starting where?: '), asDecimal,
  3874.                                      asHex) THEN
  3875.                     IF asHex <> - 1 THEN
  3876.                         ShowDisasmMemory(asHex, 16);
  3877.                 END;
  3878.             {$EndC}
  3879.             'E':
  3880.                 BEGIN
  3881.                 IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  3882.                     BEGIN
  3883.                     { Save the current script, and set it to Roman for Debugger }
  3884.                     savedScript := GetEnvirons(smKeyScript);
  3885.                     KeyScript(smRoman);
  3886.                     END;
  3887.  
  3888.                 DebugStr('Type ''G'' to return to the MacApp debugger.');
  3889.  
  3890.                 IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  3891.                     KeyScript(savedScript);
  3892.                 END;
  3893.             'F':
  3894.                 BEGIN
  3895.                 IF GetPromptedValue(AtStr(
  3896.                                         'Fields of object [hex handle, or decimal stack level #]?: '
  3897.                                           ), asDecimal, asHex, true, gotSymbol) THEN
  3898.                     IF (asDecimal >= 0) & (asDecimal < 100) & NOT gotSymbol THEN
  3899.                         ShowFields(GetRcvrAtLevel(asDecimal, pLink), FALSE)
  3900.                     ELSE
  3901.                         ShowFields(TObject(asHex), FALSE);
  3902.                 END;
  3903.  
  3904.             'G', chSpace, chOptionSpace:
  3905.                 BEGIN
  3906.                 IF ch = 'G' THEN
  3907.                     WriteLn('go…');
  3908.                 IF which = tSysError THEN
  3909.                     BEGIN
  3910.                     str := '';
  3911.                     ShowWhich(which, str, 0);
  3912.                     WriteLn('To proceed will be fatal or will go to another debugger.');
  3913.                     waiting := NOT (GetPromptedChar(AtStr('Want to proceed'), AtStr('NY'),
  3914.                                                     stdHelpProc) = 'Y');
  3915.                     END
  3916.                 ELSE
  3917.                     waiting := FALSE;
  3918.  
  3919.                 IF NOT waiting THEN
  3920.                     BEGIN
  3921.                     gSingleStep := ch = chOptionSpace;
  3922.                     IF ch = chSpace THEN
  3923.                         pStepOverStackSize := pStackSpace
  3924.                     ELSE
  3925.                         pStepOverStackSize := 0;
  3926.                     END;
  3927.                 END;
  3928.  
  3929.             'H':
  3930.                 HeapCmd;
  3931.  
  3932.             'I':
  3933.                 BEGIN
  3934.                 IF GetPromptedValue(AtStr(
  3935.                                      'Inspect what object [hex handle, or decimal stack level #]?: '
  3936.                                           ), asDecimal, asHex, true, gotSymbol) THEN
  3937.                     IF (asDecimal >= 0) & (asDecimal < 100) & NOT gotSymbol THEN
  3938.                         ShowFields(GetRcvrAtLevel(asDecimal, pLink), true)
  3939.                     ELSE
  3940.                         ShowFields(TObject(asHex), true);
  3941.                 END;
  3942.  
  3943.             'L':
  3944.                 BEGIN
  3945.                 IF GetPromptedNumber(AtStr('Local variables of procedure [stack level #]?: '),
  3946.                                      asDecimal, asHex) THEN
  3947.                     IF asDecimal <> - 1 THEN
  3948.                         ShowLocals(asDecimal, pLink);
  3949.                 END;
  3950.  
  3951.             'M':
  3952.                 IF pMoreMem = - 1 THEN
  3953.                     WriteLn('There is no more to show.')
  3954.                 ELSE IF pMoreMem = 0 THEN
  3955.                     ShowStack
  3956.                 ELSE
  3957.                     ShowMemory(pMoreMem, 16);
  3958.  
  3959.             {$IFC IncludeDisassembler}
  3960.             'µ':
  3961.                 IF pMoreMem = - 1 THEN
  3962.                     WriteLn('There is no more to show.')
  3963.                 ELSE
  3964.                     ShowDisasmMemory(pMoreMem, 16);
  3965.             {$EndC}
  3966.             'O':
  3967.                 BEGIN
  3968.                 pQuietOutput := FALSE;
  3969.                 str := GetPromptedString(AtStr('Redirect to file?: '), RedirectHelpProc);
  3970.                 IF str <> '' THEN
  3971.                     pQuietOutput := GetPromptedChar(AtStr('Disable trace in debug window'),
  3972.                                                     AtStr('NY'), stdHelpProc) = 'Y';
  3973.  
  3974.                 IF pDebugView <> NIL THEN
  3975.                     error := pDebugView.Redirect(0, @str);
  3976.                 IF error <> noErr THEN
  3977.                     WriteLn('Error redirecting output = ', error: 1);
  3978.  
  3979.                 gReportTime := pQuietOutput;
  3980.                 END;
  3981.  
  3982.             'P':
  3983.                 BEGIN
  3984.                 IF GetPromptedNumber(AtStr('Parameters of procedure [stack level #]?: '), asDecimal,
  3985.                                      asHex) THEN
  3986.                     IF asDecimal <> - 1 THEN
  3987.                         ShowParameters(asDecimal, pLink);
  3988.                 END;
  3989.  
  3990.             {$Ifc qPerform}
  3991.             'π':
  3992.                 PerfCmd;
  3993.             {$Endc}
  3994.  
  3995.             'Q':
  3996.                 IF GetPromptedChar(AtStr('Exit to shell.  Are you sure'), AtStr('NY'),
  3997.                    stdHelpProc) = 'Y' THEN               { erase prompt }
  3998.                     BEGIN
  3999.                     { Be kind to those with TApplication.Close routines }
  4000.                     IF pSavedState.gApplication <> NIL THEN
  4001.                         gApplication := pSavedState.gApplication;
  4002.                     ExitToShell;
  4003.                     END;
  4004.  
  4005.             'R':
  4006.                 ShowRecent;
  4007.  
  4008.             'S':
  4009.                 BEGIN
  4010.                 nextLevel := 0;
  4011.                 nextFrame := pLink;
  4012.                 pNextPC := ppc;
  4013.                 ShowStack;
  4014.                 END;
  4015.  
  4016.             'ß':
  4017.                 BEGIN
  4018.                 { Get ready to blow out of debugger }
  4019.                 IF GetPromptedNumber(AtStr('Error to signal with Failure?: '), asDecimal,
  4020.                    asHex) THEN
  4021.                     BEGIN
  4022.                     error := asDecimal;
  4023.                     IF GetPromptedNumber(AtStr('Message to signal with Failure?: '), asDecimal,
  4024.                                          asHex) THEN
  4025.                         BEGIN
  4026.                         message := asDecimal;
  4027.                         gReportNext := FALSE;
  4028.  
  4029.                         { Blow }
  4030.                         Failure(error, message);
  4031.                         END;
  4032.                     END;
  4033.                 END;
  4034.  
  4035.             'T':
  4036.                 BEGIN
  4037.                 pTraceToggle := NOT pTraceToggle;
  4038.                 gTracing := pTraceToggle & pTraceEnabled;
  4039.                 ShowStatus;
  4040.                 END;
  4041.  
  4042.             'W':
  4043.                 WindCmd;
  4044.  
  4045.             'X':
  4046.                 ToggleCmd;
  4047.  
  4048.         END;
  4049.         END;
  4050.  
  4051.     IF (NOT gSingleStep) & (pStepOverStackSize = 0) & (NOT gInBackground) THEN
  4052.         HiliteMenu(0);
  4053.     END;
  4054.  
  4055. {--------------------------------------------------------------------------------------------------}
  4056. {$S MADebugger}
  4057.  
  4058. PROCEDURE MADebuggerMainEntry(aWhich: ZT;
  4059.                               aPLink, aPpc: Longint);
  4060.  
  4061.     VAR
  4062.         i:                    INTEGER;
  4063.         forgotSuccess:        BOOLEAN;
  4064.         aWho:                MAName;
  4065.         pc:                 Longint;
  4066.  
  4067.     BEGIN
  4068.     IF NOT pCanEnterDebugger THEN                        { debugger is not re-entrant. But give user
  4069.                                                          a fighting chance }
  4070.         DebugStr('Re-entering the MacApp debugger which is not re-entrant. Be careful!')
  4071.     ELSE
  4072.         pCanEnterDebugger := FALSE;
  4073.  
  4074.     { make the reason we're here available to other procs }
  4075.     which := aWhich;
  4076.     pLink := aPLink;
  4077.     ppc := aPpc;
  4078.  
  4079.     pRecentIndex := BAND(pRecentIndex + 1, kRecent);    { modulo kRecent }
  4080.     WITH pRecentPC[pRecentIndex] DO
  4081.         BEGIN
  4082.         thePC := LongIntPtr(ppc)^;
  4083.         theZT := which;
  4084.         END;
  4085.  
  4086.     IF gMastReport THEN
  4087.         CheckFreeMasters
  4088.     ELSE
  4089.         pMasters := - 1;
  4090.  
  4091.     stkBreak := (which = tBegin) & ((pStackSpace > pBreakStack) | (pProcStack > pBrProcStack));
  4092.     stepBreak := (pStackSpace <= pStepOverStackSize);    { stop only if stack is same or less for
  4093.                                                          single stepping }
  4094.  
  4095.     IF pBreakCount > 0 THEN
  4096.         BEGIN
  4097.         GetProcName(ppc, className, procName);
  4098.         IF length(className) > 0 THEN
  4099.             Delete(procName, 1, length(className) + 1);
  4100.  
  4101.         FOR i := 1 TO pBreakCount DO
  4102.             BEGIN
  4103.             pAtBreak := ((length(pBreakClass[i]) = 0) | (pBreakClass[i] = className)) & (
  4104.                         (length(pBreakProc[i]) <> 0) & (pBreakProc[i] = procName));
  4105.             IF pAtBreak THEN
  4106.                 LEAVE;
  4107.             END;
  4108.         END
  4109.     ELSE
  4110.         pAtBreak := stkBreak | stepBreak;
  4111.  
  4112.     waiting := gSingleStep | pAtBreak | (which >= tProgBreak) | IsUserBreak;
  4113.  
  4114.     { Check to see if we have too few calls to Success when leaving a procedure. This might be
  4115.     the case if the user forgot to make the call or it was missed and the handler is on the stack,
  4116.     which it usually (??? always) is. }
  4117.     forgotSuccess := ((which = tEnd) | (which = tExit)) & (StripLong(LongIntPtr(pLink)^) >=
  4118.                      StripLong(gTopHandler));
  4119.     IF forgotSuccess THEN
  4120.         BEGIN
  4121.         WriteLn(
  4122.          'You''re leaving a routine without calling Success for a handler that will be destroyed.'
  4123.                 );
  4124.         pc := gTopHandler^.failPC;
  4125.         GetMethodName(Longint(@pc), aWho);
  4126.         WriteLn('Failure handler is: ', aWho);
  4127.         waiting := true;
  4128.         END;
  4129.  
  4130.     IF gTracing | gReportNext | waiting THEN
  4131.         BEGIN
  4132.         IF pQuietOutput & NOT waiting THEN
  4133.             pDebugView.ForceOutput(WrForceOff, WrForceUnchanged)
  4134.         ELSE
  4135.             pDebugView.ForceOutput(WrForceOn, WrForceUnchanged); { force output to window }
  4136.  
  4137.         IF gReportNext & (length(gReportInfo) <> 0) THEN
  4138.             BEGIN
  4139.             WriteLn(gReportInfo);
  4140.             gReportInfo := '';
  4141.             END;
  4142.  
  4143.         IF TrcEnable(true) THEN;
  4144.  
  4145.         IF NOT waiting & gReportTime THEN
  4146.             Write(TickCount: 10, ': ');
  4147.  
  4148.         IF pAtBreak THEN
  4149.             BEGIN
  4150.             IF stkBreak THEN
  4151.                 Write('(stack space) ');
  4152.             Write('broke at ');
  4153.             END
  4154.         ELSE IF gReportNext THEN
  4155.             Write('@ ')
  4156.         ELSE IF waiting THEN
  4157.             Write('stopped at ');
  4158.  
  4159.         GetFrameInfo(pLink, ppc, callerFrame, itsFrame, receiver, className, procName, rcvrHandle,
  4160.                      rcvrClass, segNum);
  4161.         ShowWhere;
  4162.  
  4163.         IF waiting THEN
  4164.             BEGIN
  4165.             CallEnter(true, pEnterProc);
  4166.  
  4167.             {$Ifc qPerform}
  4168.             oldState := DebugPerfMonitor(FALSE);
  4169.             {$Endc}
  4170.  
  4171.             WithHideFromMacAppDo(DoWaiting, FullHide);
  4172.  
  4173.             CallEnter(FALSE, pEnterProc);
  4174.  
  4175.             {$Ifc qPerform}
  4176.             IF DebugPerfMonitor(oldState) THEN;
  4177.             {$Endc}
  4178.             END;
  4179.  
  4180.         pDebugView.EndForce;
  4181.  
  4182.         END;
  4183.  
  4184.     gReportNext := FALSE;
  4185.  
  4186.     pCanEnterDebugger := true;
  4187.  
  4188.     END;
  4189.  
  4190. {--------------------------------------------------------------------------------------------------}
  4191. {$S Main}
  4192. {$Push} {$Z+} {$%+}
  4193.  
  4194. PROCEDURE %_BP;
  4195.  
  4196.     VAR
  4197.         OldA5:                Longint;
  4198.  
  4199.     BEGIN
  4200.     OldA5 := SetCurrentA5;                                {}
  4201.     IF pCanEnterDebugger THEN
  4202.         BEGIN
  4203.         pStackSpace := ord(GetCurStackBase) - ord(GetCurStackTop);
  4204.         IF pStackSpace > gMaxStackDepth THEN
  4205.             gMaxStackDepth := pStackSpace;
  4206.  
  4207.         pProcStack := LongIntPtr(GetCurStackFramePtr)^ - Longint(GetCurStackFramePtr) - 8;
  4208.  
  4209.         MADebuggerMainEntry(tBegin, Ord4(GetCurStackFramePtr), Ord4(GetCurStackFramePtr) + 4);
  4210.         END;
  4211.     OldA5 := SetA5(OldA5);                                {}
  4212.     END;
  4213. {$Pop}
  4214.  
  4215. {--------------------------------------------------------------------------------------------------}
  4216. {$S Main}
  4217. {$Push} {$Z+} {$%+}
  4218.  
  4219. PROCEDURE %_EP;
  4220.  
  4221.     VAR
  4222.         OldA5:                Longint;
  4223.  
  4224.     BEGIN
  4225.     OldA5 := SetCurrentA5;                                {}
  4226.     IF pCanEnterDebugger THEN
  4227.         BEGIN
  4228.         pStackSpace := ord(GetCurStackBase) - ord(GetCurStackTop);
  4229.         MADebuggerMainEntry(tEnd, Ord4(GetCurStackFramePtr), Ord4(GetCurStackFramePtr) + 4);
  4230.         END;
  4231.     OldA5 := SetA5(OldA5);                                {}
  4232.     END;
  4233. {$Pop}
  4234.  
  4235. {--------------------------------------------------------------------------------------------------}
  4236. {$S Main}
  4237. {$Push} {$Z+} {$%+}
  4238.  
  4239. PROCEDURE %_EX;
  4240.  
  4241.     VAR
  4242.         OldA5:                Longint;
  4243.  
  4244.     BEGIN
  4245.     OldA5 := SetCurrentA5;                                {}
  4246.     IF pCanEnterDebugger THEN
  4247.         BEGIN
  4248.         pStackSpace := ord(GetCurStackBase) - ord(GetCurStackTop);
  4249.         MADebuggerMainEntry(tExit, Ord4(GetCurStackFramePtr), Ord4(GetCurStackFramePtr) + 4);
  4250.         END;
  4251.     OldA5 := SetA5(OldA5);                                {}
  4252.     END;
  4253. {$Pop}
  4254.  
  4255. {--------------------------------------------------------------------------------------------------}
  4256. {$S MADebugger}
  4257.  
  4258. PROCEDURE EnterMacAppDebugger;                            { called by ProgramBreak in UOBJECT }
  4259.     VAR
  4260.         notADummy:            Longint;
  4261.  
  4262.     BEGIN
  4263.     notADummy := LongIntPtr(Ord4(GetCurStackFramePtr))^;{ they called ProgramBreak called
  4264.                                                          EnterMacAppDebugger: skip a level }
  4265.     MADebuggerMainEntry(tProgBreak, notADummy, notADummy + 4);
  4266.     END;
  4267.  
  4268. {--------------------------------------------------------------------------------------------------}
  4269. {$S MADebugger}
  4270. {$Push} {$Z+}
  4271.  
  4272. FUNCTION GetErrTxt(errorCode: INTEGER): Str255;
  4273.  
  4274.     BEGIN
  4275.     GetIndString(GetErrTxt, 252, errorCode);
  4276.     END;
  4277. {$Pop}
  4278.  
  4279. {--------------------------------------------------------------------------------------------------}
  4280. {$S MADebugger}
  4281. {$Push} {$Z+}
  4282.  
  4283. VAR
  4284.     e:                    Str255;
  4285.  
  4286. PROCEDURE DebugException(errorCode: INTEGER);
  4287. { 68000 exceptions (code 901-910) and SysError calls }
  4288.  
  4289.     CONST
  4290.         kUnInitStorage1     = $72677267;                { Pascal provided uninited storage }
  4291.         kUnInitStorage2     = $67726772;                { odd byte boundary of above }
  4292.         kDebugHandleInit    = $F3F3F3F3;                { Handles are inited to this in MacApp® }
  4293.         kDebugPtrInit        = $F5F5F5F5;                { Pointers are inited to this in MacApp® }
  4294.         kDebugObjInit        = $F1F1F1F1;                { Objects are inited to this in MacApp® }
  4295.  
  4296.     VAR
  4297.         notADummy:            Longint;
  4298.         accessAddr:         Longint;
  4299.         extras:             INTEGER;
  4300.         OldA5:                Longint;
  4301.         saveResLoad:        BOOLEAN;
  4302.         saveResFile:        INTEGER;
  4303.  
  4304.     BEGIN
  4305.     OldA5 := SetCurrentA5;                                {}
  4306.     saveResLoad := GetResLoad;
  4307.     SetResLoad(TRUE);
  4308.     saveResFile := MAUseResFile(gApplicationRefNum);
  4309.  
  4310.     notADummy := ord(@notADummy) + 78;                    { Where to leave continuation address =
  4311.                                                          dummy4+link4+pc4+arg2+16*reg4 }
  4312.     LongIntPtr(notADummy)^ := pSysErrPatch.oldTrapAddr; { Tentative value (worst case & disk
  4313.                                                          inserts) }
  4314.  
  4315.     IF (errorCode = - 127) |                            { Old menu not found. }
  4316.        (errorCode = - 126) |                            { Old menu bar not found. }
  4317.        (errorCode = 30) |                                { "Please insert the disk". }
  4318.        ((errorCode >= 50) & (errorCode <= 69)) |        { SADE }
  4319.        ((errorCode >= $7FF0) & (errorCode <= $7FFF))    { Reserved for system or app use. }
  4320.        THEN
  4321.         BEGIN
  4322.         { Drop through }
  4323.         END
  4324.     ELSE
  4325.         BEGIN
  4326.         IF NOT pCanEnterDebugger THEN
  4327.             DebugStr('Re-entering the MacApp exception handler which is not re-entrant. Be careful!'
  4328.                      );
  4329.  
  4330.         { If an error happens in the debugger, give up! }
  4331.         InstallInterceptors(FALSE);
  4332.  
  4333.         EmptyHandle(pReserve);                            { we need all the space we can get }
  4334.  
  4335.         WriteLn;
  4336.  
  4337.         extras := 0;
  4338.         accessAddr := 0;
  4339.         IF (errorCode DIV 100) = 9 THEN                 { 900-9xx are 68000 exceptions, not SysErr
  4340.                                                          calls }
  4341.             BEGIN
  4342.             { Where to go after this procedure returns }
  4343.             CASE (errorCode - 900) * sizeof(Longint) OF
  4344.                 exBusError:
  4345.                     Handle(notADummy)^ := pOldexBusError;
  4346.                 exAddressError:
  4347.                     Handle(notADummy)^ := pOldexAddressError;
  4348.                 exIllegalInst:
  4349.                     Handle(notADummy)^ := pOldexIllegalInst;
  4350.                 exZeroDivide:
  4351.                     Handle(notADummy)^ := pOldexZeroDivide;
  4352.                 exCheck:
  4353.                     Handle(notADummy)^ := pOldexCheck;
  4354.                 exOverflow:
  4355.                     Handle(notADummy)^ := pOldexOverflow;
  4356.                 exLineF:
  4357.                     Handle(notADummy)^ := pOldexLineF;
  4358.             END;
  4359.  
  4360.             IF errorCode = 900 THEN
  4361.                 Write('NMI Button: ')
  4362.             ELSE
  4363.                 Write('Exception #', errorCode - 900: 1, '  ');
  4364.             errorCode := errorCode - 901;
  4365.             { Thanks to Rob Hawley for improvements to the following code }
  4366.             IF (errorCode = 1) | (errorCode = 2) | (errorCode = 3) | (errorCode = 6) THEN { Bus
  4367.                    error or Address error }
  4368.                 BEGIN
  4369.                 { 68000 and 68020 have different exception stack frames }
  4370.                 IF NOT (qNeedsMC68020 | qNeedsMC68030) & (gConfiguration.processor = env68000) THEN
  4371.                     BEGIN
  4372.                     extras := 8;                        { 68000 precedes status and PC with 4 words
  4373.                                                          }
  4374.                     accessAddr := LongIntPtr(notADummy + 6)^; { which includes the access address }
  4375.                     END
  4376.                 ELSE
  4377.                     BEGIN
  4378.                     extras := 0;                        { no extra stack frame data before status
  4379.                                                          reg & PC }
  4380.                     wrlblptr('exception frame Addr', LongIntPtr(notADummy + 4));
  4381.                     WriteLn;
  4382.                     IF (errorCode = 1) | (errorCode = 2) THEN
  4383.                         BEGIN
  4384.                         wrlblptr('PC', LongIntPtr(notADummy + 4 + 2)^);
  4385.                         WriteLn;
  4386.                         accessAddr := LongIntPtr(notADummy + 20)^; { Must add 16 - 4 to get
  4387.                                                                     offending address}
  4388.                         END
  4389.                     ELSE
  4390.                         accessAddr := LongIntPtr(notADummy + 4 + 2)^; {Same as PC}
  4391.                     END
  4392.                 END
  4393.             END
  4394.         ELSE
  4395.             Write('SysErr ID = ', errorCode: 1, '  ');
  4396.  
  4397.         CASE errorCode OF                                { All SysError argument values except where
  4398.                                                          indicated }
  4399.             0..28:
  4400.                 e := GetErrTxt(errorCode + 1);
  4401.             33:
  4402.                 e := GetErrTxt(30);
  4403.             { 30, 31: ...Disk insert... }
  4404.             41:
  4405.                 e := GetErrTxt(31);
  4406.             42:
  4407.                 e := GetErrTxt(32);
  4408.             51:
  4409.                 e := GetErrTxt(33);
  4410.             81:
  4411.                 e := GetErrTxt(34);
  4412.             84:
  4413.                 e := GetErrTxt(35);
  4414.             85:
  4415.                 e := GetErrTxt(36);
  4416.             86:
  4417.                 e := GetErrTxt(37);
  4418.             100:
  4419.                 e := GetErrTxt(38);
  4420.             MAXINT:
  4421.                 e := GetErrTxt(39);
  4422.             OTHERWISE
  4423.                 IF (32 <= errorCode) & (errorCode <= 53) THEN
  4424.                     e := GetErrTxt(40)
  4425.                 ELSE
  4426.                     e := GetErrTxt(41);
  4427.         END;
  4428.  
  4429.         WriteLn(e);
  4430.         IF accessAddr <> 0 THEN
  4431.             BEGIN
  4432.             Write('Bad address was: ');
  4433.             WritePtr(accessAddr);
  4434.             WriteLn;
  4435.             IF accessAddr = kUnInitStorage1 THEN
  4436.                 WriteLn('Appears to be Pascal provided uninitialized storage.')
  4437.             ELSE IF accessAddr = kUnInitStorage2 THEN
  4438.                 WriteLn(
  4439.                       'Appears to be Pascal provided uninitialized storage at an odd byte boundary.'
  4440.                         )
  4441.             ELSE IF accessAddr = kDebugHandleInit THEN
  4442.                 WriteLn('Appears to be Handle contents initialized by debugging.')
  4443.             ELSE IF accessAddr = kDebugPtrInit THEN
  4444.                 WriteLn('Appears to be Pointer contents initialized by debugging.')
  4445.             ELSE IF accessAddr = kDebugObjInit THEN
  4446.                 WriteLn('Appears to be uninitialized instance variable.')
  4447.             END;
  4448.         gApplication.Beep(30);                            { 1/2 second }
  4449.  
  4450.         MADebuggerMainEntry(tSysError, Ord4(GetCurStackFramePtr), Ord4(GetCurStackFramePtr) + 2 + extras);
  4451.         InstallInterceptors(true);
  4452.         END;
  4453.     IF MAUseResFile(saveResFile) = 0 THEN ;
  4454.     SetResLoad(saveResLoad);
  4455.     OldA5 := SetA5(OldA5);
  4456.     END;
  4457. {$Pop}
  4458.  
  4459.  
  4460.  
  4461. {--------------------------------------------------------------------------------------------------}
  4462. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  4463. {$W+}
  4464. {$R-}
  4465. {$Init-}
  4466. {$OV-}
  4467. {$S MADebugger}
  4468.  
  4469. PROCEDURE aVBLTask;
  4470.  
  4471.     CONST
  4472.         kVBLDelay            = 15;                        { Ticks before checking }
  4473.         theOffset            = sizeof(Longint) * 2;
  4474.  
  4475.     VAR
  4476.         aKeyMap:            KeyMap;
  4477.         oldState:            INTEGER;
  4478.  
  4479.     BEGIN
  4480.  
  4481. { Set up application's A5.
  4482.   Our A5 is prepended to the QElem which is pointed at by A0 }
  4483.  
  4484.     WITH pVBLInfo DO
  4485.         pVBLInfo.aQElemWithA5.OldA5 := SetA5(VBLInfoPtr(GetParmBlockPtr - theOffset)^.aQElemWithA5.
  4486.                                              A5);
  4487.  
  4488.     oldState := IntegerPtr(JournalFlag)^;
  4489.     IntegerPtr(JournalFlag)^ := 0;                        { turn off journaling }
  4490.     GetKeys(aKeyMap);
  4491.     IntegerPtr(JournalFlag)^ := oldState;
  4492.  
  4493.     IF aKeyMap[59] & aKeyMap[55] & aKeyMap[56] & aKeyMap[58] & pCanEnterDebugger THEN
  4494.         MADebuggerMainEntry(tVBL, Ord4(GetCurStackFramePtr), Ord4(GetCurStackFramePtr) + 4);
  4495.  
  4496.     { always Reset the vblCount }
  4497.     WITH pVBLInfo DO
  4498.         BEGIN
  4499.         aQElemWithA5.q.vblQElem.vblCount := kVBLDelay;
  4500.         IF SetA5(aQElemWithA5.OldA5) = 0 THEN;            { discard the function result }
  4501.         END;
  4502.  
  4503.     END;
  4504. {$Pop}
  4505.  
  4506. {--------------------------------------------------------------------------------------------------}
  4507. {$S MAInit}
  4508.  
  4509. PROCEDURE VBLInstall;
  4510.  
  4511.     CONST
  4512.         kVBLDelay            = 15;                        { Ticks before checking }
  4513.  
  4514.     BEGIN
  4515.     IF pInterceptExceptionVectors THEN
  4516.         WITH pVBLInfo DO
  4517.             BEGIN
  4518.             { Setup the VBL task }
  4519.             WITH aQElemWithA5.q.vblQElem DO
  4520.                 BEGIN
  4521.                 qType := ord(vType);
  4522.                 vblAddr := @aVBLTask;
  4523.                 vblCount := kVBLDelay;
  4524.                 vblPhase := 0;
  4525.                 END;
  4526.             aQElemWithA5.A5 := Longint(GetA5);
  4527.             { This will make the A5 world available to the VBL task }
  4528.  
  4529.             { Install the VBL task }
  4530.             FailOSErr(VInstall(@aQElemWithA5.q));
  4531.             END;
  4532.     END;
  4533.  
  4534. {--------------------------------------------------------------------------------------------------}
  4535. {$S MADebugger}
  4536.  
  4537. PROCEDURE VBLRemove;
  4538.  
  4539. { removes the VBL task }
  4540.  
  4541.     VAR
  4542.         e:                    OSErr;
  4543.  
  4544.     BEGIN
  4545.     IF pInterceptExceptionVectors THEN
  4546.         e := VRemove(@pVBLInfo.aQElemWithA5.q);         { Discard error }
  4547.     END;
  4548.  
  4549. {--------------------------------------------------------------------------------------------------}
  4550. {$S MADebugger}
  4551.  
  4552. PROCEDURE DebugEndForce;
  4553.  
  4554.     BEGIN
  4555.     IF pDebugView <> NIL THEN
  4556.         pDebugView.EndForce;
  4557.     END;
  4558.  
  4559. {--------------------------------------------------------------------------------------------------}
  4560. {$S MADebugger}
  4561.  
  4562. PROCEDURE DebugForceOutput(DebugToWindow, DebugToFile: DebugForceOptions);
  4563.  
  4564.     BEGIN
  4565.     IF pDebugView <> NIL THEN
  4566.         pDebugView.ForceOutput(WrForceOptions(DebugToWindow), WrForceOptions(DebugToFile));
  4567.     END;
  4568.  
  4569. {--------------------------------------------------------------------------------------------------}
  4570. {$S MADebugger}
  4571.  
  4572. FUNCTION DebugRedirect(vRefnum: INTEGER;                {CONST}
  4573.                        fileName: StringPtr): OSErr;
  4574.  
  4575.     BEGIN
  4576.     IF pDebugView <> NIL THEN
  4577.         DebugRedirect := pDebugView.Redirect(vRefnum, fileName)
  4578.     ELSE
  4579.         DebugRedirect := noErr;                         {!!! think of an error to return }
  4580.     END;
  4581.  
  4582. {--------------------------------------------------------------------------------------------------}
  4583. {$S MADebugger}
  4584.  
  4585. PROCEDURE AddObjectToInspector(obj: TObject);
  4586.     EXTERNAL;
  4587.  
  4588. PROCEDURE DoToSubView(view: TView);
  4589.  
  4590.     BEGIN
  4591.     IF view.fSubViews <> NIL THEN
  4592.         AddObjectToInspector(view.fSubViews);
  4593.     AddObjectToInspector(view);
  4594.     view.EachSubView(DoToSubView);
  4595.     END;
  4596.  
  4597. PROCEDURE InitUDebugAfterIApplication;
  4598. { Call this once at the end of IApplication to finish initialization of the debugger. }
  4599.  
  4600.     BEGIN
  4601.     { do the following for each debug window }
  4602.     pDebugWindow.fNextHandler := gApplication;
  4603.     InstallIfPrintHandler(gPrintHandler, pDebugView);
  4604.  
  4605.     {$IFC qDebugTheDebugger}
  4606.     DoToSubView(pDebugWindow);
  4607.     {$ENDC}
  4608.     END;
  4609.  
  4610. {--------------------------------------------------------------------------------------------------}
  4611. {$S MADebugger}
  4612.  
  4613. PROCEDURE DebugShowTranscriptWindow;
  4614. { Call this proc from macApp to show the window }
  4615.  
  4616.     BEGIN
  4617.     IF pDebugWindow <> NIL THEN
  4618.         pDebugWindow.Open;
  4619.     END;
  4620.  
  4621. {--------------------------------------------------------------------------------------------------}
  4622. {$S MADebugger}
  4623.  
  4624. FUNCTION DebugCapture(captureProc: ProcPtr): ProcPtr;
  4625. { Install an alternative capture proc, which will get called for every
  4626. writeln. It should have the same interface as AddText. You will
  4627. probably want to set gWrToWindow to FALSE to inhibit output to the
  4628. window at the same time. Pass NIL to remove any capture proc. }
  4629.  
  4630.     BEGIN
  4631.     DebugCapture := fCaptureProc;
  4632.     fCaptureProc := captureProc;
  4633.     END;
  4634.  
  4635. {--------------------------------------------------------------------------------------------------}
  4636. {$S MADebugger}
  4637.  
  4638. FUNCTION DebugTranscriptWidth: INTEGER;
  4639. { Returns number of characters per line in current transcript window }
  4640.  
  4641.     BEGIN
  4642.     DebugTranscriptWidth := pDebugView.fCols;
  4643.     END;
  4644.  
  4645. {$EndC qDebug}
  4646. {--------------------------------------------------------------------------------------------------}
  4647. {$S Main}
  4648.  
  4649. FUNCTION DebugCanReadLn: BOOLEAN;
  4650. { Returns True if you can readln to the user }
  4651.  
  4652.     BEGIN
  4653.     DebugCanReadLn := (pDebugView <> NIL) & pDebugView.fWrToWindow & pUDebugInitialized;
  4654.     END;
  4655.  
  4656. {--------------------------------------------------------------------------------------------------}
  4657. {$S Main}
  4658.  
  4659. FUNCTION DebugCanWriteLn: BOOLEAN;
  4660. { Returns True if you can writeln to the user }
  4661.  
  4662.     BEGIN
  4663.     DebugCanWriteLn := (pDebugView <> NIL) & pUDebugInitialized;
  4664.     END;
  4665.  
  4666. {--------------------------------------------------------------------------------------------------}
  4667. {$S Main}
  4668.  
  4669. PROCEDURE GetCallersMethodName(VAR s: MAName);
  4670.  
  4671.     BEGIN
  4672.     GetMethodName(LongIntPtr(GetCurStackFramePtr)^ + 4, s); { report about our caller's caller }
  4673.     END;
  4674.  
  4675. {--------------------------------------------------------------------------------------------------}
  4676. {$S Main}
  4677.  
  4678. PROCEDURE GetMethodName(ppc: Longint;
  4679.                         VAR s: MAName);
  4680. { GetMethodName returns the name of the method (or procedure) in
  4681. which ppc points. }
  4682.  
  4683.     BEGIN
  4684.     GetProcName(ppc, discardStr, s);
  4685.     END;
  4686.  
  4687. {--------------------------------------------------------------------------------------------------}
  4688. {$S Main}
  4689.  
  4690. PROCEDURE GetProcName(ppc: Longint;
  4691.                       VAR className, procName: MAName);
  4692. { GetProcName returns the name of the procedure or function in
  4693. which ppc points.  If it is in a method, then it return's
  4694. the name of the method's class in className. }
  4695.  
  4696.     VAR
  4697.         pc, nextPC, limit:    Ptr;
  4698.         index:                INTEGER;
  4699.  
  4700.     BEGIN
  4701.     pc := Handle(ppc)^;
  4702.     IF (ord(pc) <> 0) & NOT Odd(ord(pc)) THEN
  4703.         BEGIN
  4704.         limit := Ptr(ord(pc) + 32767);
  4705.         WHILE (endOfModule(pc, limit, @procName, nextPC) = NIL) DO
  4706.             BEGIN
  4707.             IF ord(pc) >= ord(limit) THEN
  4708.                 BEGIN
  4709.                 className := '';
  4710.                 procName := '';
  4711.                 LEAVE;
  4712.                 END
  4713.             ELSE
  4714.                 pc := Ptr(ord(pc) + 2);
  4715.             END;
  4716.  
  4717.         index := pos('.', procName);
  4718.         IF index <> 0 THEN
  4719.             BEGIN
  4720.             className := copy(procName, 1, index - 1);
  4721.             END
  4722.         ELSE
  4723.             className := '';
  4724.         END
  4725.     ELSE
  4726.         BEGIN
  4727.         className := '';
  4728.         procName := '';
  4729.         END;
  4730.     END;
  4731.  
  4732. {--------------------------------------------------------------------------------------------------}
  4733. {$S MADebugger}
  4734.  
  4735. FUNCTION TrcEnable(okToTrace: BOOLEAN): BOOLEAN;
  4736. { Control whether tracing from %_BP/%_EP/%_EX is enabled or not.  Set to false when the section
  4737. of code that you are using doesn't really need to be traced (like the inspector or debugger itself).}
  4738.  
  4739.     BEGIN
  4740.     TrcEnable := pTraceEnabled;
  4741.     pTraceEnabled := okToTrace;
  4742.     gTracing := pTraceToggle & pTraceEnabled;
  4743.     END;
  4744.  
  4745. {--------------------------------------------------------------------------------------------------}
  4746. {$S MADebugger}
  4747.  
  4748. PROCEDURE IDUDebug;
  4749. { Writeln UDebug compile time. }
  4750.  
  4751.     BEGIN
  4752.     WRITELN('UDebug of 14 Feb 90 (Valentine''s Day), Compiled on ', COMPDATE, ' @ ', COMPTIME);
  4753.     END;
  4754.